移动语义如何保存临时变量的数据
How does move semantics preserve data of temporary variables?
我正在阅读这篇文章:什么是移动语义?
请注意,在那篇文章中给出的移动构造函数的例子是:
string(string&& that)
{
data = that.data;
that.data = nullptr;
}
当我们使用string a(x+y)
来构造一个新字符串时,我发现它令人困惑。由于x+y
的结果是一个临时变量,它很快就会被破坏。这意味着在原始数据(应该存储在函数调用完成后清理的x+y
的堆栈帧中)被销毁后,通过指针(data = that.data
)进行复制实际上就是通过悬挂指针进行复制。将that.data
设置为nullptr似乎没有帮助,因为堆栈帧无论如何都会被清理掉。
有人能解释为什么这不是一个问题吗?c++实际上是如何处理这种情况的?
当你这样做时:
string a(x + y);
它相当于:
string temp(x + y);
string a(move(temp));
//destroy temp
您引用的move构造函数的相关代码将a
作为this
,that
作为temp
,因此它可以内联为:
string temp(x + y);
string a(/*uninitialized*/);
a.data = temp.data;
temp.data = nullptr;
//destroy temp
正如您所看到的,temp.data
是被置空的,因此temp
的析构函数变成了no-op,实际数据在a
内部保留,正如预期的那样。
你的困惑似乎来自data
的起源。在最简单的string
实现中,string::data
始终是动态分配的内存块:
string(const char *str)
{
size_t len = strlen(str);
data = new char[len + 1];
strcpy(data, len);
}
~string()
{
delete[] data;
}
即使在堆栈上分配了string
,例如temp
和a
,甚至可能是x
和y
,它们的data
存储块也是动态的。
的确,现实世界中的string
实现通常进行非动态短字符串优化。但如果你这样做,那么move构造函数(和任何其他成员函数)就会有点复杂。
由于x+y的结果是一个临时变量,它很快就会被破坏。这意味着在指针上复制(data=That.data)实际上就是在悬挂指针上复制
没有。复制指针,使新字符串现在具有数据,然后将临时对象的指针设置为nullptr
,使临时对象销毁时不会删除字符串数据。
你可以在这个的小例子中看到它是如何工作的
#include <iostream>
struct Foo
{
int * f;
Foo(int size) : f(new int[size])
{
for (int i = 0; i < size; i++)
f[i] = i;
}
Foo() : f(nullptr) {}
~Foo() { delete [] f; }
};
int main()
{
int size = 10;
Foo b; // b is empty
{
Foo f(size); // now f has an of size 10
// if we now swap the contents like the move operation does
b.f = f.f;
f.f = nullptr;
} // f goes out of scope and ~Foo() is called
// now here b.f is valid as delete on nullptr did nothing
for (int i = 0; i < size; i++)
std::cout << b.f[i] << " ";
}
实时示例
在string
的情况下,数据存储在堆上,而不是堆栈帧中。"字符串"对象只包含指针,可能还包含一些附加数据(例如长度)。因此,您显示的move构造函数有效地"剥夺"了that
对象对其数据的所有权。第二行,将nullptr
分配给临时的数据指针,是必要的,以避免同一临时的析构函数删除我们窃取的数据(因为在nullptr上调用delete保证不会产生任何效果)。
- 尝试通过OCI例程从Oracle获取blob数据,但出现错误:ORA-01008:并非所有变量都绑定
- 我可以在 C++ 中将数据成员/变量从其定义之外添加到结构中吗?
- 从模板创建通用打印函数,以打印基元数据类型变量的值
- 如何在变量中插入多种不同长度的数据类型?
- 如果变量数据包含大于 vector 所有元素的整数,则仅在视觉工作室上接收"矢量下标超出范围"?
- 面临在 if 语句之外打印变量数据的问题 完成使用 Qt 编程
- 有没有办法"QByteArray"变量数据直接放入变量"int"而无需强制转换?
- 如何在一行中从不同的变量(数据类型)创建一个字符数组?
- 从保存变量数据类型的数据结构中检索值,而不指定返回类型
- 从字符串中读取变量数据
- 返回对成员变量数据的引用的开销
- 如何将C 变量数据放入System()函数中
- C++生成器 XE 2 -- 如何在 TEdit 控件中显示变量数据
- 定义C++变量:数据类型(值)
- 静态变量/数据和对象
- 将非成员变量数据传递给构造函数时,如何保存它们并在其他成员函数中使用?C++
- 将变量数据发送到其他类时出现问题
- 如何从变量数据创建std::initializer_list
- 将c++的变量数据类型转换为c#
- 如何在C++中存储变量数据