如何在C ++ 11

时间:2016-05-09 14:03:34

标签: c++ c++11 parameter-passing return-value

我真的很担心在C ++ 11中返回大数据。什么是最有效的方式? 这是我的相关功能:

void numericMethod1(vector<double>& solution,
                    const double input);

void numericMethod2(pair<vector<double>,vector<double>>& solution1,
                    vector<double>& solution2,
                    const double input1,
                    const double input2);

以下是我使用它们的方式:

int main()
{
    // apply numericMethod1
    double input = 0;
    vector<double> solution;
    numericMethod1(solution, input);

    // apply numericMethod2
    double input1 = 1;
    double input2 = 2;
    pair<vector<double>,vector<double>> solution1;
    vector<double> solution2;
    numericMethod2(solution1, solution2, input1, input2);

    return 0;
}

问题是,std :: move()在以下实现中是否无效?

实施:

void numericMethod1(vector<double>& solution,
                    const double input)
{
    vector<double> tmp_solution;

    for (...)
    {
    // some operation about tmp_solution
    // after that this vector become very large
    }

    solution = std::move(tmp_solution);
}

void numericMethod2(pair<vector<double>,vector<double>>& solution1,
                    vector<double>& solution2,
                    const double input1,
                    const double input2)
{
    vector<double> tmp_solution1_1;
    vector<double> tmp_solution1_2;
    vector<double> tmp_solution2;

    for (...)
    {
    // some operation about tmp_solution1_1, tmp_solution1_2 and tmp_solution2
    // after that the three vector become very large
    }

    solution1.first = std::move(tmp_solution1_1);
    solution1.second = std::move(tmp_solution1_2);
    solution2 = std::move(tmp_solution2);
}

如果它们没用,我如何处理这些大的返回值而无需多次复制? 免费更改API!

更新

感谢StackOverFlow和这些答案,在深入研究相关问题之后,我更了解这个问题。由于RVO,我更改了API,为了更清楚,我不再使用std :: pair。在这里,是我的新代码:

struct SolutionType
{
    vector<double> X;
    vector<double> Y;
};

SolutionType newNumericMethod(const double input1,
                              const double input2);

int main()
{
    // apply newNumericMethod
    double input1 = 1;
    double input2 = 2;
    SolutionType solution = newNumericMethod(input1, input2);

    return 0;
}

SolutionType newNumericMethod(const double input1,
                              const double input2);
{
    SolutionType tmp_solution; // this will call the default constructor, right?
    // since the name is too long, i make alias.
    vector<double> &x = tmp_solution.X;
    vector<double> &y = tmp_solution.Y;

    for (...)
    {
    // some operation about x and y
    // after that these two vectors become very large
    }

    return tmp_solution;
}

我怎么知道RVO发生了?或者我如何确保 RVO发生?

4 个答案:

答案 0 :(得分:9)

按价值返回,依靠RVO (return value optimization)

auto make_big_vector()
{
    vector<huge_thing> v1;
    // fill v1

    // explicit move is not necessary here        
    return v1;
} 

auto make_big_stuff_tuple()
{
    vector<double> v0;
    // fill v0

    vector<huge_thing> v1;
    // fill v1

    // explicit move is necessary for make_tuple's arguments,
    // as make_tuple uses perfect-forwarding:
    // http://en.cppreference.com/w/cpp/utility/tuple/make_tuple

    return std::make_tuple(std::move(v0), std::move(v1));
}

auto r0 = make_big_vector();
auto r1 = make_big_stuff_tuple();

我会将函数的API更改为仅按值返回。

答案 1 :(得分:3)

您可以使用std::vector::swap成员函数,它将容器的内容与其他内容交换。 不会对单个元素调用任何移动,复制或交换操作。

solution1.first.swap(tmp_solution1_1);
solution1.second.swap(tmp_solution1_2);
solution2.swap(tmp_solution2);

编辑:

这些陈述并非毫无用处,

solution1.first = std::move(tmp_solution1_1);
solution1.second = std::move(tmp_solution1_2);
solution2 = std::move(tmp_solution2);

他们调用了std::vector::operator=(&&)的移动赋值运算符,它确实在右侧移动了向量。

答案 2 :(得分:2)

如果您拥有非常大的vector<double>这样的大数据,您仍然可以按值返回,因为C ++ 11的移动语义将会启动对于std::vector,所以从函数返回它只是某种指针赋值(因为vector<double>的内容通常是堆分配引擎盖下。)

所以我会这样做:

// No worries in returning large vectors by value
std::vector<double> numericMethod1(const double input)
{
    std::vector<double> result;

    // Compute your vector<double>'s content
    ...

    // NOTE: Don't call std::move() here.
    // A simple return statement is just fine.
    return result;
}

(请注意,基于特定的C ++编译器,也可以应用C ++ 98/03中已有的其他类型的优化,如RVO / NRVO。)

相反,如果你有一个方法返回多个输出值,那么我会使用非const引用,就像在C ++ 98/03中一样:

void numericMethod2(pair<vector<double>,vector<double>>& output1,
                    vector<double>& output2,
                    vector<double>& output3,
                    ...
                    const double input1,
                    const double input2);

在实现中,您仍然可以使用“swap-timization”的有效C ++ 98/03技术,您只需调用std::swap()来交换局部变量并输出参数:

#include <utility> // for std::swap

void numericMethod2(pair<vector<double>,vector<double>>& solution1,
                    vector<double>& solution2,
                    const double input1,
                    const double input2)

{
    vector<double> tmp_solution1_1;
    vector<double> tmp_solution1_2;
    vector<double> tmp_solution2;

    // Some processing to compute local solution vectors
    ...

    // Return output values to caller via swap-timization
    swap(solution1.first, tmp_solution1_1);
    swap(solution1.second, tmp_solution1_2);
    swap(solution2, tmp_solution2);
}

交换向量通常将内部向量的指针交换到向量所拥有的堆分配内存:所以你只有指针赋值不是深拷贝,内存重新分配或类似的昂贵操作。

答案 3 :(得分:1)

首先,为什么不直接在numericMethod2中使用solution1?这更直接。

与std :: array或obj []不同,该值不存储在堆栈中,而是使用堆(您可以参考标准库代码,它们使用operator new()很多)。所以,如果你发现vector只是临时的并且将返回到其他地方,那么使用std :: swap或std :: move。函数返回实际上可以转换为xvalue

标准容器(std :: map,std :: set,deque,list等)总是如此