简体   繁体   English

用C ++返回对象

[英]Returning an object in C++

I am learning C++ from a background of mostly C and Java and I am curious on what is the best way to return an object in C++ without having to copy the object. 我是从C和Java为主的背景学习C ++的,我很好奇在没有复制对象的情况下以C ++返回对象的最佳方法是什么。 From my understanding, C++11 introduced rvalue references (&&) to move data from a temporary variable (as oppose to copying). 根据我的理解,C ++ 11引入了右值引用(&&),以从临时变量(反对复制)移动数据。 Example: 例:

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

std::string &&hello = getStr();

Another way I could think of is using a shared pointer. 我可以想到的另一种方法是使用共享指针。

std::tr1::shared_ptr<std::string> getStr(){

    std::tr1::shared_ptr<std::string> hello(new std::string("Hello"));
    return hello;

}

auto hello = getStr();

I am thinking maybe an rvalue reference is better but I'd like a second opinion first before I use it. 我想也许右值引用会更好,但是在使用它之前我想先征求第二意见。 Which is better? 哪个更好?

Also is it recommended that fields in a class be rvalue references if they won't be set using the constructor? 如果不使用构造函数设置它们,是否还建议将类中的字段作为右值引用? Example: 例:

class StringHolder{

   public:
     std::string &&str;
};

StringHolder sh;
sh.str = getStr();

Thank you guys very much! 非常感谢你们!

This question will probably be closed as a duplicate. 这个问题可能会重复出现。 It is an oft-asked question. 这是一个经常提出的问题。 However I would like to answer it anyway. 但是我还是想回答。

In C++11, when you are the client of an object like std::string , you should pass it around by value and not worry so much about efficiency: 在C ++ 11中,当您是std::string之类的对象的客户端时,应按值传递它,而不必太担心效率:

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

std::string hello = getStr();

At this level you do not need to be concerned with rvalue references. 在此级别上,您无需关心右值引用。 Just know that std::string can "copy" from rvalues (such as the return from getStr() ) very efficiently. 只是知道std::string可以非常高效地从rvalues(例如getStr()的返回getStr() “复制”。 This "copy" is actually called a "move" and is enabled automatically because you are copying from an rvalue (an anonymous temporary). 该“副本”实际上称为“移动”,由于您是从右值(匿名临时副本)进行复制而自动启用的。

Don't try to optimize copying by reverting to reference counting. 不要尝试通过恢复引用计数来优化复制。 Only use reference counting if you need shared ownership semantics . 仅在需要共享所有权语义时才使用引用计数。 This statement isn't always true. 这个说法并不总是正确的。 But for learning the basics, it is close enough that it is a good rule of thumb to follow. 但是对于学习基础知识来说,它非常接近,这是遵循的良好经验法则。

You need to start worrying about rvalue references when you design your class that needs to be passed around by value: 在设计需要按值传递的类时,您需要开始担心右值引用:

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

For a brief introduction to rvalue references and move semantics, N2027 is a decent tutorial. 为了简要介绍右值引用和移动语义, N2027是一个不错的教程。 N2027 is too long to be pasted in here, but short enough to be an easy read. N2027太长而无法在此处粘贴,但又足够短以方便阅读。 std::string follows the basics laid down in N2027 to enable you to pass it around by value guilt free. std::string遵循N2027中规定的基本原则,使您可以无罪地传递它。 And you can follow those same design patterns in your Widget . 您可以在Widget遵循相同的设计模式。

Often you can avoid copies by returning a const reference to a member variable. 通常,您可以通过将const引用返回给成员变量来避免复制。 For example: 例如:

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

This is equivalent to return &center in execution and in fact will likely be inlined simply resulting in direct (read-only) access of the member from the caller. 这等效于执行中的return &center ,实际上可能会内联,只是导致调用者对成员的直接(只读)访问。

In cases where you construct a temporary to return the compiler may elide the extra copy as an optimization, requiring no special syntax on your part. 如果您构造了一个临时文件以返回,则编译器可能会将多余的副本作为一种优化而删除,不需要您使用特殊的语法。

By default you should simply pass things by value. 默认情况下,您应该只按值传递事物。 If a function does not need to modify or copy a parameter then it can be taken by const& , but otherwise just take parameters by value. 如果某个函数不需要修改或复制参数,则可以由const& ,否则可以按值获取参数。 Return objects by value and leave it to move semantics or RVO to avoid a copy. 按值返回对象,并将其保留以移动语义或RVO以避免复制。


C++ uses and encourages passing objects 'by-value'. C ++使用并鼓励按“值”传递对象。 Move semantics are a feature that allows code to do this while making fewer copies than before they were introduced. 移动语义是一项功能,它允许代码在进行复制的同时比引入之前减少副本。 Typically code does not need to use rvalue reference types directly in order to gain the benefit of move semantics. 通常,代码无需直接使用右值引用类型即可获得移动语义的好处。 This is because temporary objects are rvalues and overload resolution will automatically select methods that take rvalue references. 这是因为临时对象是右值,并且重载解析将自动选择采用右值引用的方法。

For example: 例如:

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

std::string hello = getStr();

This code uses move semantics. 此代码使用移动语义。 return "Hello" constructs a string temporary and so the constructor used to initialize the return value object will be the move constructor (though actually the return value optimization will almost certainly avoid this move). return "Hello"构造一个临时字符串,因此用于初始化返回值对象的构造函数将是move构造函数(尽管实际上,返回值优化几乎肯定会避免此移动)。 Then the value returned by getStr() is a temporary, so the constructor selected for string hello is again the move constructor. 然后, getStr()返回的值是一个临时值,因此为string hello选择的构造函数再次是move构造函数。

I think you can also do std::string &&hello = getStr(); 我认为您也可以执行std::string &&hello = getStr(); , but it's probably not necessary since hello will already be move constructed. ,但这可能不是必需的,因为hello已经被移动构造了。

Another way I could think of is using a shared pointer 我能想到的另一种方法是使用共享指针

I don't think smart pointers are a generally a good idea unless you really need the specific ownership semantics they provide. 除非您真的需要智能指针提供的特定所有权语义,否则我认为智能指针通常不是一个好主意。 Using straightforward 'by-value' passing is a good default and move semantics generally allow you to use it without extra copying. 使用简单的“按值”传递是一个很好的默认值,并且移动语义通常允许您无需额外复制就可以使用它。

Also is it recommended that fields in a class be rvalue references if they won't be set using the constructor? 如果不使用构造函数设置它们,是否还建议将类中的字段作为右值引用?

No, member references are not usually a good idea. 不,成员推荐通常不是一个好主意。 They make things more complicated and you aren't even allowed to use them as your example shows. 它们使事情变得更加复杂,并且您甚至无法如示例所示使用它们。 If your example code were allowed then sh.str = getStr(); 如果您的示例代码被允许,则sh.str = getStr(); would be undefined behavior, because you're trying to assign to a non-existant object. 这将是未定义的行为,因为您正试图分配给不存在的对象。 It's like std::string *str; *str = getStr(); 就像std::string *str; *str = getStr(); std::string *str; *str = getStr(); .

Rvalue refernces will be much faster, as they are an intrinsic language feature, rather than a reference counting class. 右值引用将更快,因为它们是语言的固有功能,而不是引用计数类。 Using a smart or shared pointer here will give no gain, and greatly decrease clarity. 在此处使用智能指针或共享指针不会带来任何收益,并且会大大降低清晰度。 However, the rvalue references are a part of the language designed for this kind of thing. 但是,右值引用是为此类语言设计的一部分。 Use the rvalue reference. 使用右值引用。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM