我理解在C ++程序员中鼓励使用值语义。但在我的工作中,我注意到一些程序员使用引用语义的模式,确切地说,他们使用shared_ptr,我将使用值语义。
为了给这个提供一点上下文,例如,我有一个API,它读取数据库页面并返回其内容。我看到有两种方法可以做到。
选择1值语义:
DBPage readDatabasePage(int number) { // number is the for which page to read
DBPage page;
... // reading the database page
return page; // here we have RVO/move semantic to help us so it is not inefficient
}
选择2参考语义:
std::shared_ptr<DBPage> readDatabasePage(int number) { // ditto
std::shared_ptr<DBPage> page = std::make_shared<DBPage>();
...
return page;
}
第二种选择对我来说似乎没问题,因为我看不出这样做的缺点。所以我想要理解的是为什么我们鼓励人们使用价值语义。选择2有什么问题?
答案 0 :(得分:2)
默认值语义是首选,因为它没有分配内存=&gt;没有内存泄漏,没有损坏的内存等。
每个指针类型都有自己的语义。仅当shared_ptr
所控制的资源将共享时才应使用shared_ptr
,因此它最重要的是它将持续到最后一个引用(指针)。在您的示例中,DBPage
不合适。如果希望在您的示例中使用指针(例如unique_ptr
太大而无法存储在堆栈中),则它应为unique_ptr
。
您的示例可能不完整,之后结果确实会被分享&#34;。我要说的是,即使在这种情况下,shared_ptr
也应该被使用,之后将被转换为&#34;到shared_ptr
,否则功能签名会产生误导,有时它是用户唯一可见的东西。虽然在这种情况下它是有争议的。
此外,unique_ptr
比std::move
慢,并且比int.operator++
慢得多,因为它使用原子操作进行引用计数。与简单{{1}}相比,它们非常昂贵,但它仅在性能危急情况下才会出现问题。
答案 1 :(得分:1)
这取决于DBPage的复制成本。例如,如果DBPage是一个包含一些指向数据的指针的类,那么复制它可能很便宜,而将它存储在shared_ptr
中可能会增加不必要的开销。
另一方面,也许DBPage复制起来很昂贵。你提到RVO并移动语义,从函数返回DBPage时这些都很好,但是如果用户实际上想要保留两个引用相同数据的变量,并且他们希望数据的生命周期是两个变量的最大值#39;一生,然后shared_ptr
是天生的契合。
如果用户最终需要shared_ptr<DBPage>
但你给他们DBPage
,他们可能需要复制数据才能获得他们想要的内容。
简而言之,您需要了解您的用户和正在使用的实际数据。
答案 2 :(得分:0)
您有两种不同的情况需要创建对象。你的价值语义&#34;在您希望某些内存成为返回对象(堆栈内存,数组中的内存等)的情况下,可以正常工作。你的&#34;参考语义&#34;当您希望对象的生命周期超出其范围(并在堆中生存)时非常有用。
要明确解决您的问题,当您想要将结果存储在std::vector<DBPage>
时,选项2将无法使用。即使使用移动语义,为工作提供正确的功能也是更好的选择。