【问题标题】:Why doenst STL vector call default constructor on allocation?为什么 STL 向量在分配时不调用默认构造函数?
【发布时间】:2014-12-14 10:57:27
【问题描述】:

我得到了以下代码块:

#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 都应该保存在一个向量中。因此,在实施移动分配和 ctor 并删除了复制分配和 ctor。

现在在我看来,向量在分配新内存时不会调用我的 TestStruct 的默认构造函数。为什么会这样以及如何让向量在内存分配上调用默认构造函数?我需要自己的分配器吗?

【问题讨论】:

  • 请使用有效的入口点之一。 void main() 不是其中之一。
  • -1 用于void main。不要那样做。
  • @Cheersandhth.-Alf +1 反击。 void main 不会使问题变得或多或少有用。
  • @immibis: void main 向没有思想的读者教授 void main。我会说你符合要求。是的,这确实使问题变得不那么有用了。
  • @Cheersandhth.-Alf 我同意不使用void main() 的说法,我不同意-1。代码当然有错误;这就是OP在这里的原因-学习。这个问题本身问得很好,有一个独立的代码示例,实际结果,预期结果,显示了努力 - 简而言之,这是一个在我看来不值得反对的好问题。

标签: c++ vector stl allocation


【解决方案1】:

您的问题是您的移动构造函数实现不正确。它在新创建的对象和被移动的对象之间交换wasCreated,但新创建的对象中的变量尚未初始化(默认构造的布尔值未知)。因此,您使用 TestStruct() 创建的临时对象会收到一个未初始化的布尔值,在您的情况下恰好是 true,因此在它们的析构函数中调用了 DoImportantStuff()

所以移动构造函数应该如下所示:

// implement only move assignment & ctor
TestStruct(TestStruct&& other) : wasCreated(other.wasCreated) {
    other.wasCreated = false;
}

(您已将所有权转移到新创建的对象,旧对象不再拥有任何东西。)

不要将赋值运算符与构造函数混淆;他们做不同的事情。赋值运算符处理两个都已经构造的对象;在构造函数的情况下,正在构造的对象,嗯……尚未构造,所以它没有有效的状态。

顺便说一句,emplace_back() 对您的使用方式毫无意义。其目的是将其参数直接转发给向量内对象的构造函数。由于您有一个默认构造函数(无参数),因此调用应该是:

testVector.emplace_back();

这将在原地默认构造TestStruct

【讨论】:

    【解决方案2】:

    现在在我看来,向量在分配新内存时不会调用我的 TestStruct 的默认构造函数。

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

    如果您希望向量默认构造一些对象,请调整它的大小。

    【讨论】:

    • 当我同时写 testVector.resize(10);std::vector&lt;TestStruct&gt; testVector(10); DoImportantStuff() 时被调用。
    猜你喜欢
    • 2011-09-23
    • 1970-01-01
    • 1970-01-01
    • 2021-04-23
    • 1970-01-01
    • 2020-10-10
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    相关资源
    最近更新 更多