gpt4 book ai didi

c++ - std::move 如何使原始变量的值无效?

转载 作者:太空宇宙 更新时间:2023-11-04 15:12:17 26 4
gpt4 key购买 nike

以下示例来自 cpp reference :

#include <iostream>
#include <utility>
#include <vector>
#include <string>

int main()
{
std::string str = "Hello";
std::vector<std::string> v;

// uses the push_back(const T&) overload, which means
// we'll incur the cost of copying str
v.push_back(str);
std::cout << "After copy, str is \"" << str << "\"\n";

// uses the rvalue reference push_back(T&&) overload,
// which means no strings will be copied; instead, the
// Contents of str will be moved into the vector. This is
// less expensive, but also means str might now be empty.
v.push_back(std::move(str));
std::cout << "After move, str is \"" << str << "\"\n";

std::cout << "The contents of the vector are \"" << v[0]
<< "\", \"" << v[1] << "\"\n";
}

使用std::move 可能会导致原始值丢失。对我来说,它看起来像

v.push_back(std::move(str))

导致创建新成员 v[1]。然后,

&v[1] = &str

但为什么它会破坏 str 中的值呢?这没有意义。

有很多关于 std::move 的复杂教程,比我自己的问题更难理解。

谁能写一下

v.push_back(std::move(str))

使用 c++03 的等价物?

我寻找一个解释,它的理解很容易,并且不包含诸如 x-valuestatic_castremove_reference 等先决条件,因为他们自己需要首先理解 std::move。请避免这种循环依赖。

这些链接也没有回答我的问题:7510182 , 3413470

因为我感兴趣的是 str 的危害,而不是 v[1] 会发生什么。

也欢迎使用像c++03这样简单的伪代码。


更新:为了避免复杂化,让我们考虑一个更简单的 int 示例,如下所示

int x = 10;
int y = std::move(x);
std::cout << x;

最佳答案

根据实现,std::move 可以是内部内存地址的简单交换。

如果您在 http://cpp.sh/9f6ru 上运行以下代码

#include <iostream>
#include <string>

int main()
{
std::string str1 = "test";
std::string str2 = "test2";

std::cout << "str1.data() before move: "<< static_cast<const void*>(str1.data()) << std::endl;
std::cout << "str2.data() before move: "<< static_cast<const void*>(str2.data()) << std::endl;

str2 = std::move(str1);
std::cout << "=================================" << std::endl;

std::cout << "str1.data() after move: " << static_cast<const void*>(str1.data()) << std::endl;
std::cout << "str2.data() after move: " << static_cast<const void*>(str2.data()) << std::endl;
}

您将获得以下输出:

str1.data() before move: 0x363d0d8
str2.data() before move: 0x363d108
=================================
str1.data() after move: 0x363d108
str2.data() after move: 0x363d0d8

但结果可能因编译器和标准库的实现而异。

但实现细节可能更加复杂http://cpp.sh/6dx7j .如果您查看您的示例,那么您会发现为字符串创建拷贝并不一定需要为其内容分配新内存。这是因为几乎所有对 std::string 的操作都是只读的或需要分配内存。所以实现可以决定只做浅拷贝:

#include <iostream>
#include <string>
#include <vector>

int main()
{
std::string str = "Hello";
std::vector<std::string> v;

std::cout << "str.data() before move: "<< static_cast<const void*>(str.data()) << std::endl;

v.push_back(str);
std::cout << "============================" << std::endl;
std::cout << "str.data() after push_back: "<< static_cast<const void*>(str.data()) << std::endl;
std::cout << "v[0].data() after push_back: "<< static_cast<const void*>(v[0].data()) << std::endl;

v.push_back(std::move(str));
std::cout << "============================" << std::endl;

std::cout << "str.data() after move: "<< static_cast<const void*>(str.data()) << std::endl;
std::cout << "v[0].data() after move: "<< static_cast<const void*>(v[0].data()) << std::endl;
std::cout << "v[1].data() after move: "<< static_cast<const void*>(v[1].data()) << std::endl;
std::cout << "After move, str is \"" << str << "\"\n";


str = std::move(v[1]);
std::cout << "============================" << std::endl;
std::cout << "str.data() after move: "<< static_cast<const void*>(str.data()) << std::endl;
std::cout << "v[0].data() after move: "<< static_cast<const void*>(v[0].data()) << std::endl;
std::cout << "v[1].data() after move: "<< static_cast<const void*>(v[1].data()) << std::endl;
std::cout << "After move, str is \"" << str << "\"\n";
}

输出是

str.data() before move: 0x3ec3048
============================
str.data() after push_back: 0x3ec3048
v[0].data() after push_back: 0x3ec3048
============================
str.data() after move: 0x601df8
v[0].data() after move: 0x3ec3048
v[1].data() after move: 0x3ec3048
After move, str is ""
============================
str.data() after move: 0x3ec3048
v[0].data() after move: 0x3ec3048
v[1].data() after move: 0x601df8
After move, str is "Hello"

如果你看一下:

#include <iostream>
#include <string>
#include <vector>

int main()
{
std::string str = "Hello";
std::vector<std::string> v;

std::cout << "str.data() before move: "<< static_cast<const void*>(str.data()) << std::endl;

v.push_back(str);
std::cout << "============================" << std::endl;
str[0] = 't';
std::cout << "str.data() after push_back: "<< static_cast<const void*>(str.data()) << std::endl;
std::cout << "v[0].data() after push_back: "<< static_cast<const void*>(v[0].data()) << std::endl;

}

那么您会假设 str[0] = 't' 只会替换原位的数据。但不一定是这样http://cpp.sh/47nsy .

str.data() before move: 0x40b8258
============================
str.data() after push_back: 0x40b82a8
v[0].data() after push_back: 0x40b8258

move 基元,如:

void test(int i) {
int x=i;
int y=std::move(x);
std::cout<<x;
std::cout<<y;
}

大部分会被编译器完全优化掉:

  mov ebx, edi
mov edi, offset std::cout
mov esi, ebx
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov edi, offset std::cout
mov esi, ebx
pop rbx
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int) # TAILCALL

std::cout 使用相同的寄存器,xy 被完全优化掉。

关于c++ - std::move 如何使原始变量的值无效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51916526/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com