用C ++返回一个对象

时间:2012-07-08 00:34:28

标签: c++ c++11

我从大多数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();

非常感谢你们!

5 个答案:

答案 0 :(得分:10)

此问题可能会以副本形式结束。这是一个经常被问到的问题。但无论如何我想回答。

在C ++ 11中,当你是像std::string这样的对象的客户端时,你应该按价值传递它,而不用担心效率:

std::string getStr(){
   return "Hello";
}

std::string hello = getStr();

在此级别,您无需关注右值引用。只需知道std::string可以有效地从rvalues(例如从getStr()返回非常)“复制”。这个“副本”实际上被称为“移动”并自动启用,因为您正在从右值(匿名临时)进行复制。

请勿尝试通过恢复引用计数来优化复制。如果您需要共享所有权语义,则仅使用引用计数。此语句不始终为true。但是为了学习基础知识,它足够接近,这是一个很好的经验法则。

当你设计需要按值传递的类时,你需要开始担心rvalue引用:

class Widget
{
    // pointer to heap data
public:
    // ...
};

对于rvalue引用和移动语义的简要介绍,N2027是一个不错的教程。 N2027太长了,无法粘贴在这里,但足够短,易读。 std::string遵循N2027中规定的基础知识,使您能够通过价值无罪传递它。您可以在Widget中使用相同的设计模式。

答案 1 :(得分:2)

通常可以通过将const引用返回到成员变量来避免副本。例如:

class Circle {
    Point center;
    float radius;
public:
    const Point & getCenter() const { return center; };
};

这相当于执行中的return &center,实际上可能只是内联,导致成员从调用者直接(只读)访问。

如果你构造一个临时的返回,编译器可能会将额外的副本作为优化而删除,不需要你的特殊语法。

答案 2 :(得分:2)

默认情况下,您应该按值传递内容。如果某个函数不需要修改或复制参数,那么它可以由const&获取,但只能按值获取参数。按值返回对象并使其移动语义或RVO以避免复制。


C ++使用并鼓励传递对象'by-value'。移动语义是一种允许代码执行此操作的功能,同时制作的副本比引入之前的副本少。通常,代码不需要直接使用rvalue引用类型,以获得移动语义的好处。这是因为临时对象是rvalues,重载决策将自动选择采用右值引用的方法。

例如:

std::string getStr(){
   return "Hello";
}

std::string hello = getStr();

此代码使用移动语义。 return "Hello"构造一个临时字符串,因此用于初始化返回值对象的构造函数将是移动构造函数(尽管实际上返回值优化几乎肯定会避免此移动)。然后getStr()返回的值是临时的,因此为string hello选择的构造函数也是移动构造函数。

我认为你也可以std::string &&hello = getStr();,但可能没有必要,因为hello已经被移动构建了。

  

我能想到的另一种方法是使用共享指针

除非你真的需要他们提供的特定所有权语义,否则我认为智能指针通常不是一个好主意。使用直接的“按值”传递是一个很好的默认值,移动语义通常允许您使用它而无需额外复制。

  

如果不使用构造函数设置类中的字段,建议将它们作为右值引用吗?

不,会员参考通常不是一个好主意。它们使事情变得更加复杂,甚至不允许您使用它们作为示例节目。如果允许您的示例代码,那么sh.str = getStr();将是未定义的行为,因为您正在尝试分配给不存在的对象。这就像std::string *str; *str = getStr();

答案 3 :(得分:1)

Rvalue引用会快得多,因为它们是一种内在语言功能,而不是引用计数类。在这里使用智能或共享指针将不会获得任何收益,并且大大降低了清晰度。但是,对于这种事情,右值引用是设计语言的一部分。使用右值参考。

答案 4 :(得分:0)

如果你想在这种情况下使用智能指针,也许unique_ptr是一个更好的选择。