简体   繁体   English

为什么函数返回不移动向量?

[英]Why does function return not move vector?

I'm using C++17 after a long stint with C# and working through some Project Euler problems to get my feet well. 经过很长时间的C#工作后,我正在使用C ++ 17,并通过一些Euler问题解决了我的问题。 Anyway, can anyone explain why createRandomVector(const int n) is not "moving" the vector created? 无论如何,任何人都可以解释为什么createRandomVector(const int n)没有“移动”创建的向量吗? I output the memory addresses and they only stay the same when passed by reference (obviously). 我输出内存地址,并且它们仅在通过引用传递时保持不变(很明显)。 Below is the code: 下面是代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <random>

using namespace std;

auto createRandomVector(const int n)
{
    vector<int> v(n);

    iota(begin(v), end(v), 1);
    shuffle(begin(v), end(v), std::mt19937());

    cout << &v << endl;
    return v;
}

void printVector(const vector<int>& v, ostream& os);

int main()
{
    auto v = createRandomVector(100);
    printVector(v, cout);

    cout << endl;

    cout << &v << endl;
    return 0;
}


void printVector(const vector<int>& v, ostream& os)
{
    cout << &v << endl;
    for_each(begin(v), end(v), [&os](auto& i)
    {
        os << i << " ";
    });
}

Here is the output: 这是输出:

00BBFC20
00BBFD38
100 73 64 ... 85 90
00BBFD38

Why does the 1st memory address not match the 2nd? 为什么第一存储器地址与第二存储器地址不匹配? I have some understanding of how move works in modern C++ (a static_cast). 我对移动在现代C ++中的工作方式有一些了解(static_cast)。 But why is this not working? 但是为什么这不起作用?

There's 2 issues here: moving, and copy elision. 这里有两个问题:移动和复制省略。

First of all, moving: Move means that there are two different objects and the contents of one are transferred to the other. 首先,移动: 移动意味着存在两个不同的对象,并且其中一个的内容转移到了另一个。 (As opposed to the contents of one being copied to the other). (与将一个内容复制到另一个内容相反)。 In C++ an object has a fixed address for its entire lifetime. 在C ++中,对象在整个生命周期中都有固定的地址。

Example snippet: 示例片段:

vector<int> a { 1, 2, 3, 4, 5 };
vector<int> b;
cout << &a << ", " << &a[0] << '\n';
b = std::move(a);
cout << &b << ", " << &b[0] << '\n';

I didn't run this so hopefully there are no typoes but you should see that, even though the two vectors are different, the block of int objects has been transferred from one to the other. 我没有运行此命令,因此希望它没有错别字,但您应该看到,即使两个向量不同, int对象块也已从一个转移到另一个。

If you add to your program an output of &v[0] you should see this same effect. 如果将&v[0]的输出添加到程序中,则应该会看到相同的效果。


Secondly, copy elision . 其次, 复制省略 The C++ Standard makes it optional, in this scenario, for the local variable v in createRandomVector to actually be created in the memory space set aside for v in main . 在这种情况下,C ++标准使其成为可选,以便在为main v预留的存储空间中实际创建createRandomVector的局部变量v In which case there would not even be any move or copy operation associated with the return step. 在这种情况下,甚至没有任何与return步骤相关的移动或复制操作。

The conditions this can happen are when a function returns by value, and the return statement has the form: return X; 当函数按值返回并且return语句的形式为: return X;可能发生的情况return X; where X is the name of a local variable with no embellishment. 其中X是没有修饰的局部变量的名称。

If the compiler does take this option then the first two outputs of your program would be the same. 如果编译器确实采用了此选项,则程序的前两个输出将是相同的。 Apparently, your compiler only decides to do this in Release Mode. 显然,您的编译器仅决定在发布模式下执行此操作。

Why does the 1st memory address not match the 2nd? 为什么第一存储器地址与第二存储器地址不匹配?

They are different objects, so there is no requirement for them to have the same memory address. 它们是不同的对象,因此不需要它们具有相同的内存地址。

However, second object might reuse the storage of the first. 但是,第二个对象可能会重用第一个对象的存储。 Such optimisation - that is, constructing the local automatic variable in place of the return value thereby eliding its copy-initialization (by move) from the local variable - is called named return value optimisation . 这种优化-即构造局部自动变量来代替返回值,从而从局部变量中消除(通过移动)其副本初始化-被称为返回值优化

The return value itself is a temporary though, and there is another move from the temporary into the local variable in the calling scope. 虽然返回值本身是一个临时值,但在调用范围内还有一个从临时值到局部变量的移动。 This move can also be elided. 此举也可以忽略。 Edit: No longer applies since C++17. 编辑:自C ++ 17起不再适用。

So, another answer to your question would be: Because the compiler did not either perform named return value optimisation , or it didn't elide the move from the return value. 因此,另一种回答你的问题是:由于编译器没有执行 任何 命名返回值优化 ,或者它不从的Elid返回值的举动。 Such optimisations are not mandatory, and are performed at the discretion of the compiler. 这样的优化不是强制性的,而是由编译器决定是否执行。

in Debug I get different results with &v but in Release mode I get the same. 在Debug中,我用&v得到了不同的结果,但是在Release模式下,我得到了相同的结果。

It is quite typical for compilers to not perform certain optimisations in debug mode. 对于编译器而言,在调试模式下不执行某些优化是非常典型的。

Why does function return not move vector? 为什么函数返回不移动向量?

The vector was moved in the sense that v was move-constructed. 该载体在这个意义上移动 v是移动构造的。 But it appears that you mean something else by "move". 但是看来您通过“移动”还具有其他含义。

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

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