我得到了以下代码块:
#include <vector>
#include <iostream>
struct TestStruct {
bool wasCreated;
TestStruct() {
std::cout << "Default Constructor" << std::endl;
wasCreated = false;
}
~TestStruct() {
if (wasCreated) {
DoImportantStuff();
}
}
void Create() {
wasCreated = true;
}
// delete all copy stuff
TestStruct(const TestStruct&) = delete;
TestStruct& operator=(const TestStruct&) = delete;
// implement only move assignment & ctor
TestStruct(TestStruct&& other) {
std::swap(wasCreated, other.wasCreated);
}
TestStruct& operator=(TestStruct&& other) {
std::swap(wasCreated, other.wasCreated);
return *this;
}
// very important stuff
void DoImportantStuff() {
std::cout << "Do Important Stuff" << std::endl;
}
};
int main() {
std::vector<TestStruct> testVector;
testVector.emplace_back(TestStruct());
testVector.emplace_back(TestStruct());
std::cin.get();
}
此代码导致输出:
默认构造函数
做重要的事情
默认构造函数
做重要的事情
做重要的事情
基本上我想编写一个拥有内存但只在我调用Create()
时才分配内存的类。为了避免内存泄漏并避免删除未分配的内存,我引入了wasCreated
,这只有在我调用Create()
时才会出现。每个TestStruct都应保存在一个向量中。因此,在实施移动分配&amp; ctor并删除了副本分配和&amp;构造函数。
现在在我看来,当它分配新内存时,向量doenst会调用我的TestStruct的默认构造函数。为什么会这样,如何让向量在内存分配上调用默认构造函数?我需要自己的分配器吗?
答案 0 :(得分:3)
您的问题是您的移动构造函数实现不正确。它在新创建的对象和正在移动的对象之间交换wasCreated
,但新创建的对象中的变量尚未初始化(默认构造的bool具有未知值) 。因此,使用TestStruct()
创建的临时对象会收到未初始化的bool,在您的情况下恰好为true
,因此在其析构函数中调用DoImportantStuff()
。
所以移动构造函数看起来应该是这样的:
// implement only move assignment & ctor
TestStruct(TestStruct&& other) : wasCreated(other.wasCreated) {
other.wasCreated = false;
}
(您已将所有权移至新创建的对象,旧版本不再拥有任何内容。)
不要将赋值运算符与构造函数混淆;他们做不同的事情。赋值运算符处理两个都已构造的对象;在构造函数的情况下,正在构造的对象是......,还没有构造,因此它没有有效的状态。
顺便说一下,emplace_back()
对您使用它的方式毫无意义。其目的是将其参数直接转发给向量内对象的构造函数。由于您有默认构造函数(无参数),因此调用应为:
testVector.emplace_back();
这将默认构建TestStruct
。
答案 1 :(得分:0)
现在在我看来,当我的TestStruct分配新内存时,向量doenst会调用我的TestStruct的默认构造函数。
默认构造的向量大小为零,因此没有要构造的对象。
如果你想让向量默认构造一些对象,请调整它的大小。