为什么STL向量不会在分配时调用默认构造函数?

时间:2014-12-14 10:57:28

标签: c++ vector stl allocation

我得到了以下代码块:

#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的默认构造函数。为什么会这样,如何让向量在内存分配上调用默认构造函数?我需要自己的分配器吗?

2 个答案:

答案 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的默认构造函数。

默认构造的向量大小为零,因此没有要构造的对象。

如果你想让向量默认构造一些对象,请调整它的大小。