以下列功能为例
string print()
{
return (some string that has been formed);
};
现在可以说这个打印函数会形成一个非常大的字符串,需要返回到从另一个类调用它的函数。
现在说这个打印功能可能会被调用数千次。有没有更正确,更快捷的方法呢?
在Visual Studio中,您可以执行此操作
void print(string& lines)
{
lines = (some string that has been formed);
};
然而g ++不会编译它,也不应该这样做,因为这可能是一个临时对象,可能在任何时候消失。所以根据我的理解,我可以做到这一点
void print(const string& lines)
{
};
如果我想要的只是在这个字符串中检索某些内容而无需修改它并快速完成。但我确实想修改它。所以我不能这样做。
这引出了我的问题是声明一个指向对象的新指针将成为最快的方法吗?还是慢一点?或者它是不值得的。即(不确定这是否会起作用?)
void print(string* lines)
{
string formedString; // the string that has been formed
lines = formedString&;
};
最后,如果我在运行时加载对象,并通过以下方法将它们添加到树中:
void add(const ItemType& item)
{
someNode->item = item;
};
item
最初是在调用此add()
的函数范围内的临时存储对象,因此将它分配给节点会导致调用函数的堆栈保持更长时间然后需要吗?或者这样可以吗?我以后能够编辑item
,还是现在被卡住了?
只是学习思想的问题:)
答案 0 :(得分:8)
只需返回字符串即可完成。
编译器将使用返回值优化(或命名返回值优化)来消除返回时字符串的额外副本。一个真正新的编译器还将为std::string
提供一个移动构造函数和移动赋值运算符,这将为完成相同的事情提供更大的保证。
编辑(抱歉,我最初错过了最后一个问题):在该函数返回后,分配一个值 not 保留函数的任何本地值。当函数返回时,将销毁其所有局部变量 。如果您将该函数的值分配给它返回后持续的值,那就没有问题 - 它将被复制(或可能移动)到目标。如果保留指向该局部的指针或引用,则在函数返回后它将悬空,因此尝试使用引用或取消引用指针将导致UB。
根据具体情况,后者可能是您要使用shared_ptr
的情况,因此函数和外部代码都将共享对数据的访问权限,只有当 对它的引用都被破坏时,数据才会被销毁。
答案 1 :(得分:2)
在C ++ 11或具有基本C ++ 11功能的编译器中,答案是:
想要速度?使用支持移动语义的对象按值传递。
您的string
类型(无论是std::string
还是您拥有的)应该支持快速移动语义。
如果从函数返回局部变量,则在C ++ 11下将隐式移入返回值。如果函数的主体在调用者站点中是可见的,并且您有一个变量是函数的返回值,那么NRVO可能会发生,导致没有发生任何副本或移动(而是实际构建的对象最终在呼叫站点。)
每当你想最终复制传入的参数时,同样在参数中使用pass-by-value。这可以允许调用者在几个上下文中执行pass-by-move,并且调用者可以在非自动上下文中显式std::move
,以提供相当不错的性能。
如果您没有制作副本,请通过const string&
传递,该string&
可以绑定到临时副本。
如果要修改数据,请通过string
或传递{{1}},然后将新字符串作为返回值的一部分返回。对于快速移动构造,第二个几乎与最坏情况下的第一个一样快,并且在某些情况下可以更快(理论上可以在第二种情况下多次链接NRVO!)