5

Prior to C++11, if I had a function that operated on large objects, my instinct would be to write functions with this kind of prototype.

void f(A &return_value, A const &parameter_value);

(Here, return_value is just a blank object which will receive the output of the function. A is just some class which is large and expensive to copy.)

In C++11, taking advantage of move semantics, the default recommendation (as I understand it) is the more straightforward:

A f(A const &parameter_value);

Is there ever still a need to do it the old way, passing in an object to hold the return value?

4

3 回答 3

7

其他人已经涵盖了A可能没有廉价移动构造函数的情况。我假设你A这样做。但是还有另一种情况,您可能希望传入“out”参数:

如果A是某种类型,例如vectororstring并且已知“out”参数已经具有可以在 内部重用的资源(例如内存)f,那么如果可以的话,重用该资源是有意义的。例如考虑:

void get_info(std::string&);
bool process_info(const std::string&);

void
foo()
{
    std::string info;
    for (bool not_done = true; not_done;)
    {
        info.clear();
        get_info(info);
        not_done = process_info(info);
    }
}

与:

std::string get_info();
bool process_info(const std::string&);

void
foo()
{
    for (bool not_done = true; not_done;)
    {
        std::string info = get_info();
        not_done = process_info(info);
    }
}

在第一种情况下,容量将string随着循环的执行而增加,然后该容量可能会在循环的每次迭代中重用。在第二种情况下string,每次迭代都会分配一个新的(忽略小字符串优化缓冲区)。

现在这并不是说你永远不应该std::string按值返回。只是您应该意识到这个问题并根据具体情况应用工程判断。

于 2012-06-16T13:19:02.283 回答
3

一个对象可能很大并且复制起来很昂贵,并且移动语义无法改进复制。考虑:

struct A {
    std::array<double,100000> m_data;
};

以这种方式设计对象可能不是一个好主意,但是如果由于某种原因您有一个这种类型的对象并且您想编写一个函数来填充数据,那么您可以使用 out 参数来完成。

于 2012-06-16T05:00:46.020 回答
3

这取决于:您的编译器是否支持返回值优化,您的函数是否f设计为能够使用您的编译器支持的 RVO?

如果是这样,那么是的,无论如何都要按值返回。通过传递一个可变参数,您将一无所获,而通过这种方式,您将获得大量的代码清晰度。如果不是,那么您必须调查 的定义A

对于某些类型,移动只不过是副本。如果A不包含任何真正值得移动的东西(指针转移所有权等),那么你将不会通过移动获得任何东西。毕竟,搬家不是免费的。它只是一个知道原件拥有的任何东西都被转移到副本的副本。如果该类型不拥有任何东西,那么移动只是一个副本。

于 2012-06-16T05:09:40.420 回答