我可以在构造函数中以两种不同的方式初始化
std::shared_ptr
成员(这两种方式都会增加其 use_count
):
通过引用:
class MyClass {
std::shared_ptr<std::string> s1;
public:
MyClass(std::shared_ptr<std::string>& s2): s1{s2} {}
};
按值传递
class MyClass2 {
std::shared_ptr<std::string> s1;
public:
MyClass2(std::shared_ptr<std::string> s2): s1{std::move(s2)} {}
};
测试程序:
int main() {
std::shared_ptr<std::string> s2 = std::make_shared<std::string>("Hello World");
MyClass myClass {s2};
MyClass2 myClass2 {s2};
std::cout << "Use count:" << s2.use_count() << std::endl;
return 0;
}
结果:
Use count:3
我认为第二种方式比第一种方式没有任何优势。 我认为永远不应该使用第二种方式,因为有一个额外的移动操作。
就性能而言,您认为哪种方式初始化
std::shared_ptr
更好?
我可以根据下面的内容更新
MyClass
,这样它就可以这样调用:
MyClass myClass {std::make_shared<std::string>("Hello World")};
class MyClass {
std::shared_ptr<std::string> s1;
public:
MyClass(const std::shared_ptr<std::string>& s2): s1{s2} {}
};
我认为性能会在太多循环中产生影响。
#include <iostream>
#include <memory>
#include <chrono>
using namespace std;
class MyClass {
std::shared_ptr<std::string> s1;
public:
MyClass(const std::shared_ptr<std::string>& s2): s1{s2} {}
};
class MyClass2 {
std::shared_ptr<std::string> s1;
public:
MyClass2(std::shared_ptr<std::string> s2): s1{std::move(s2)} {}
};
int main() {
std::shared_ptr<std::string> s2 = std::make_shared<std::string>("Hello Wolrd");
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 10000000; i++) {
MyClass myClass {s2};
}
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<float> duration = end - start;
std::cout << duration.count() << std::endl;
start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 10000000; i++) {
MyClass2 myClass2 {s2};
}
end = std::chrono::high_resolution_clock::now();
duration = end - start;
std::cout << duration.count() << std::endl;
return 0;
}
在线c++编译器和c++17
0.358915
0.623789
第一种方式需要至少有一个
shared_ptr
的副本(从s2
到s1
),无论调用函数做什么,这需要抓取锁、递增和递减引用计数以及其他开销。
另外,由于第一个版本需要一个 shared_ptr&
,那么如果调用函数有一个临时 shared_ptr&&
,那么他们将被迫在构造类之前将其存储在变量中:
std::shared_ptr<std::string> s2 = std::make_shared<std::string>("Hello World");
MyClass myClass {s2};
第二种方式允许调用者将
shared_ptr
值移动到构造函数中,然后将其直接移动到 s1
中。移动操作更便宜:它们不需要锁,并且不增加或减少引用计数。他们的速度快得离谱。此外,由于第二个只接受一个值,因此可以以任何方式构造它,因此可以直接从临时变量构造:
MyClass myClass {std::make_shared<std::string>("Hello World")};
所以第二种方式在各方面都更优越。
在我的测试中反映了您的测试,
move
版本快了约 10%。
https://quick-bench.com/q/P3pX-bC8kRXSEmqJw2_KSz-kc0s