【问题标题】:std::move triggered destructor?std::move 触发析构函数?
【发布时间】:2020-05-20 09:19:30
【问题描述】:

我正在适应带有参数const vector<pair<int32_t, A>>& as 的接口。

为了避免多重构造和多重破坏,我写CreateAs如下。

我原以为它会触发 create move del 一次,但结果却触发了两次 movedel

  • 是什么原因?
  • 我这样做是为了让A 对象可以自动销毁自己,即使有new 但没有delete。我做得对吗?

复制它:https://repl.it/@unix1/ShrillFirsthandAdvance

#include <iostream>
#include <vector>

using namespace std;

struct A {
    A() { cout << "A()" << endl; }
    A(int32_t a) : a_(a) { cout << "Create A: " << a << endl; }
    A(const A& oa) { a_ = oa.a_; cout << "Copy A: " << oa.a_ << endl; }
    A(A& oa) { a_ = oa.a_; cout << "Copy A non-const: " << oa.a_ << endl;  }
    A(const A&& oa) { a_ = oa.a_; cout << "Move A: " << oa.a_ << endl; }
    A(A&& oa) { a_ = oa.a_; cout << "Move A non-const: " << oa.a_ << endl; }
    ~A() { cout << "Del A: " << a_ << ", ptr: " << this << endl; }

    int32_t a_;
};

void CreateAs(vector<pair<int32_t, A>>& as) {

    as.reserve(3);
    for (int32_t i = 0; i < 3; ++i) {
        A* a = new A(i*i);
        cout << "a ptr: " << &a << endl;
        cout << "-----before insert----" << endl;
        as.emplace_back(make_pair(i, move(*a)));
        cout << "-----after insert-----" << endl;
    }
}

void Test() {
    vector<pair<int32_t, A>> as;
    cout << "-----Create begin----" << endl;
    CreateAs(as);
    cout << "-----Create end------" << endl;
    for (const auto& item : as) {
        cout << item.first << "->" << item.second.a_ << endl;
    }
}

int main(int32_t argc, char* argv[]) {
    Test();
    cout << "____end test____" << endl;
    return 0;
}

【问题讨论】:

  • make_pairpair 中构造一个Aemplace_backpairA 移动到向量中。从pair 移动的被销毁,同时也销毁了包含的A
  • 为什么不只是as.emplace_back(i, std::move(*a));?这就是安置的目的。
  • 注意:您的 for 循环会造成内存泄漏。使用new A(i*i); 创建的对象永远不会被销毁,它会参与移动,但move 不会销毁您从中移动的对象。
  • @RoyHuang 内存不会被回收。您必须明确地 delete 使用 new 创建的每个指针
  • @RoyHuang 是的,那是你创建的向量中As 的破坏,而不是你newed 的内存。如果你在 for 循环的末尾添加一个 delete a;,你会看到一组额外的析构函数在运行。

标签: c++ c++11 stl


【解决方案1】:

make_pair 在一对中构造一个Aemplace_backpairA 移动到向量中。从pair 移动的被销毁,同时也销毁了包含的A

【讨论】:

  • 它在make_pair 上触发了哪个构造函数,我在打印的消息中看不到它。
  • 移动构造函数。第一个移动到pair 中的make_pair。第二次从临时pair 移入向量。析构函数在销毁临时pair
【解决方案2】:

为了避免任何动作,你可以这样做

void CreateAs(std::vector<std::pair<int32_t, A>>& as) {
    as.reserve(3);
    for (int32_t i = 0; i < 3; ++i) {
        as.emplace_back(i, i*i);
    }
}

Demo

您目前有额外的make_pair

【讨论】:

  • 正如您的演示所示,它甚至根本没有调用move 构造函数?为什么?
  • emplace_back 使用给定的参数构造适当的位置,例如 new (&amp;as.back()) std::pair&lt;int32_t, A&gt;(i, i*i)
猜你喜欢
  • 1970-01-01
  • 2014-03-13
  • 2013-12-08
  • 2015-02-14
  • 2022-12-23
  • 1970-01-01
  • 2017-08-21
  • 1970-01-01
  • 2014-01-02
相关资源
最近更新 更多