虽然重构了一些代码,但我遇到了一些返回std :: string的getter方法.像这样的东西例如:
class foo
{
private:
std::string name_;
public:
std::string name()
{
return name_;
}
};
Run Code Online (Sandbox Code Playgroud)
当然吸气者会更好地回归const std::string&
?当前方法返回的副本效率不高.会返回一个const引用会导致任何问题吗?
Dim*_*ima 55
这可能导致问题的唯一方法是调用者存储引用,而不是复制字符串,并在对象被销毁后尝试使用它.像这样:
foo *pFoo = new foo;
const std::string &myName = pFoo->getName();
delete pFoo;
cout << myName; // error! dangling reference
Run Code Online (Sandbox Code Playgroud)
但是,由于您的现有函数返回一个副本,因此您不会破坏任何现有代码.
Ogr*_*m33 29
实际上,另一个特别是不通过引用返回字符串的问题是通过c_str()方法std::string
通过指向内部的指针提供访问的事实.这让我花了很多时间调试头痛.例如,假设我想从foo获取名称,并将其传递给JNI以用于构造jstring以便稍后传入Java,并且返回副本而不是引用.我可能写这样的东西:const char*
name()
foo myFoo = getFoo(); // Get the foo from somewhere.
const char* fooCName = foo.name().c_str(); // Woops! foo.name() creates a temporary that's destructed as soon as this line executes!
jniEnv->NewStringUTF(fooCName); // No good, fooCName was released when the temporary was deleted.
Run Code Online (Sandbox Code Playgroud)
如果你的调用者要做这种事情,最好使用某种类型的智能指针或const引用,或者至少在你的foo.name()方法上有一个讨厌的警告注释标题.我提到JNI,因为以前的Java编码器可能特别容易受到这种类似的链接方法的影响,而这种方法似乎无害.
pae*_*bal 17
const引用返回的一个问题是,如果用户编码如下:
const std::string & str = myObject.getSomeString() ;
Run Code Online (Sandbox Code Playgroud)
有了std::string
回报,直到STR超出范围的临时对象将仍然活着,并连接到海峡.
但是会发生什么const std::string &
?我的猜测是,我们会对一个对象的const引用,当它的父对象解除分配时它会死掉:
MyObject * myObject = new MyObject("My String") ;
const std::string & str = myObject->getSomeString() ;
delete myObject ;
// Use str... which references a destroyed object.
Run Code Online (Sandbox Code Playgroud)
所以我倾向于const引用返回(因为,无论如何,我只是更喜欢发送一个引用,而不是希望编译器会优化额外的临时),只要遵守以下合同:"如果你想超越它我的对象存在,他们在我的对象被破坏之前复制它"
rle*_*lut 10
std :: string的一些实现共享具有写时复制语义的内存,因此按值返回几乎与返回引用一样有效,并且您不必担心生命周期问题(运行时确实如此)它适合你).
如果你担心性能,那么对它进行基准测试(<=不能压力那么大!!!)尝试两种方法并测量增益(或缺乏增益).如果一个人更好而你真的在乎,那就用它吧.如果没有,那么更喜欢按价值进行保护,它会再次提供其他人提到的终身问题.
你知道他们对做出假设的看法......
好的,所以返回副本和返回引用之间的区别是:
表现:返回参考可能会更快,也可能不会更快; 它取决于std::string
您的编译器实现如何实现(正如其他人指出的那样).但即使你返回引用,函数调用后的赋值通常也会涉及一个副本,如std::string name = obj.name();
安全:返回参考可能会也可能不会引起问题(悬挂参考).如果您的函数的用户不知道他们在做什么,将引用存储为引用并在提供对象超出范围后使用它,那么就会出现问题.
如果你想快速安全地使用boost :: shared_ptr.您的对象可以在内部存储字符串shared_ptr
并返回shared_ptr
.这样,就不会复制对象,并且它总是安全的(除非你的用户拔出原始指针get()
并在你的对象超出范围之后用它做东西).