[英]Returning an object in C++
我是从C和Java为主的背景学习C ++的,我很好奇在没有复制对象的情况下以C ++返回对象的最佳方法是什么。 根据我的理解,C ++ 11引入了右值引用(&&),以从临时变量(反对复制)移动数据。 例:
std::string getStr(){
return "Hello";
}
std::string &&hello = getStr();
我可以想到的另一种方法是使用共享指针。
std::tr1::shared_ptr<std::string> getStr(){
std::tr1::shared_ptr<std::string> hello(new std::string("Hello"));
return hello;
}
auto hello = getStr();
我想也许右值引用会更好,但是在使用它之前我想先征求第二意见。 哪个更好?
如果不使用构造函数设置它们,是否还建议将类中的字段作为右值引用? 例:
class StringHolder{
public:
std::string &&str;
};
StringHolder sh;
sh.str = getStr();
非常感谢你们!
这个问题可能会重复出现。 这是一个经常提出的问题。 但是我还是想回答。
在C ++ 11中,当您是std::string
之类的对象的客户端时,应按值传递它,而不必太担心效率:
std::string getStr(){
return "Hello";
}
std::string hello = getStr();
在此级别上,您无需关心右值引用。 只是知道std::string
可以非常高效地从rvalues(例如getStr()
的返回getStr()
“复制”。 该“副本”实际上称为“移动”,由于您是从右值(匿名临时副本)进行复制而自动启用的。
不要尝试通过恢复引用计数来优化复制。 仅在需要共享所有权语义时才使用引用计数。 这个说法并不总是正确的。 但是对于学习基础知识来说,它非常接近,这是遵循的良好经验法则。
在设计需要按值传递的类时,您需要开始担心右值引用:
class Widget
{
// pointer to heap data
public:
// ...
};
为了简要介绍右值引用和移动语义, N2027是一个不错的教程。 N2027太长而无法在此处粘贴,但又足够短以方便阅读。 std::string
遵循N2027中规定的基本原则,使您可以无罪地传递它。 您可以在Widget
遵循相同的设计模式。
通常,您可以通过将const引用返回给成员变量来避免复制。 例如:
class Circle {
Point center;
float radius;
public:
const Point & getCenter() const { return center; };
};
这等效于执行中的return ¢er
,实际上可能会内联,只是导致调用者对成员的直接(只读)访问。
如果您构造了一个临时文件以返回,则编译器可能会将多余的副本作为一种优化而删除,不需要您使用特殊的语法。
默认情况下,您应该只按值传递事物。 如果某个函数不需要修改或复制参数,则可以由const&
,否则可以按值获取参数。 按值返回对象,并将其保留以移动语义或RVO以避免复制。
C ++使用并鼓励按“值”传递对象。 移动语义是一项功能,它允许代码在进行复制的同时比引入之前减少副本。 通常,代码无需直接使用右值引用类型即可获得移动语义的好处。 这是因为临时对象是右值,并且重载解析将自动选择采用右值引用的方法。
例如:
std::string getStr(){
return "Hello";
}
std::string hello = getStr();
此代码使用移动语义。 return "Hello"
构造一个临时字符串,因此用于初始化返回值对象的构造函数将是move构造函数(尽管实际上,返回值优化几乎肯定会避免此移动)。 然后, getStr()
返回的值是一个临时值,因此为string hello
选择的构造函数再次是move构造函数。
我认为您也可以执行std::string &&hello = getStr();
,但这可能不是必需的,因为hello
已经被移动构造了。
我能想到的另一种方法是使用共享指针
除非您真的需要智能指针提供的特定所有权语义,否则我认为智能指针通常不是一个好主意。 使用简单的“按值”传递是一个很好的默认值,并且移动语义通常允许您无需额外复制就可以使用它。
如果不使用构造函数设置它们,是否还建议将类中的字段作为右值引用?
不,成员推荐通常不是一个好主意。 它们使事情变得更加复杂,并且您甚至无法如示例所示使用它们。 如果您的示例代码被允许,则sh.str = getStr();
这将是未定义的行为,因为您正试图分配给不存在的对象。 就像std::string *str; *str = getStr();
std::string *str; *str = getStr();
。
右值引用将更快,因为它们是语言的固有功能,而不是引用计数类。 在此处使用智能指针或共享指针不会带来任何收益,并且会大大降低清晰度。 但是,右值引用是为此类语言设计的一部分。 使用右值引用。
如果要在这种情况下使用智能指针,也许unique_ptr是更好的选择。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.