在C++中返回一个对象
Returning an object in C++
我学习C++的背景主要是C和Java,我很想知道在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
可以非常有效地"复制"右值(例如getStr()
的返回)。这种"复制"实际上被称为"移动",并且是自动启用的,因为您是从rvalue(匿名临时)复制的。
不要试图通过恢复引用计数来优化复制。只有在需要共享所有权语义时才使用引用计数。这句话并不总是正确的。但对于学习基础知识来说,这是一条很好的经验法则。
当你设计需要按值传递的类时,你需要开始担心右值引用:
class Widget
{
// pointer to heap data
public:
// ...
};
对于右值引用和移动语义的简要介绍,N2027是一个不错的教程。N2027太长了,不能粘贴在这里,但足够短,便于阅读。std::string
遵循N2027中规定的基本原则,使您能够通过价值观传递它,而不会感到内疚。您可以在Widget
中遵循相同的设计模式。
通常可以通过返回对成员变量的常量引用来避免复制。例如:
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();
。
Rvalue引用将更快,因为它们是一个内在的语言功能,而不是引用计数类。在这里使用智能或共享指针不会带来任何好处,而且会大大降低清晰度。然而,右值引用是为这类事情设计的语言的一部分。使用右值引用。
如果您想在这种情况下使用智能指针,也许unique_ptr是更好的选择。
- 如何通过另一个对象中的命令正确地从一个对象返回数据
- 我可以制作一个对象方法,如果单独调用,它将自行修改,但如果在复制初始化期间调用,则会返回一个新对象?
- 函数,返回一个对象数组
- c++返回一个对象的const引用
- 在C++中返回一个对象
- 返回一个对象:值、指针和引用
- SWIG:从另一个模块返回对象的函数
- 乍一看,构造函数返回了一个对象
- 删除由另一个函数返回的指针指向的对象
- 我怎样才能得到一个v8函数来返回一个c++对象
- 如何在Cython中从另一个包装对象返回包装的c++对象
- 在C++中,我想从一个函数返回一个对象数组,并在另一个函数中使用它
- Objective-C:如果我在ARC的函数中返回一个c++对象,它会创建一个副本吗?我是否必须手动释放该副本?
- 返回一个对象的纯虚方法
- 从函数返回一个对象
- c++从类方法返回一个对象数组
- 我的函数返回一个对象,但我无法通过返回值访问对象的属性。
- 构造一个对象以在其他地方按值返回
- 如何让getter返回另一个对象的指针
- 当返回一个对象时,为什么要将创建+初始化和返回作为两个单独的语句,而不是一个