移动 class 个持有 unique_ptr 的实例

move class instance holding a unique_ptr

我有一个包含 class 个实例的向量。这些实例中的每一个都有一个 unique_ptr 到另一个 class。 因为我从不尝试复制 class 实例甚至共享指针,所以我觉得 unique_ptr 比 shared_ptrs 更合适,因为指针不共享,但只能通过 class实例。

这是不好的做法吗?为什么这行不通?我知道将实例复制到唯一指针的格式不正确,但由于我移动了它,所以我不明白为什么不允许这样做?

我必须创建自定义移动构造函数吗?它应该做什么?

一旦从向量中删除对象实例,就应该删除唯一的 ptr,因为没有留下任何引用,对吗?

为了更好地理解代码示例:

class A {
private:
    int number;

public:
    void f() {
        std::cout << "The number is: " << number;
    }
    A(int i) : number{i} {}
    ~A() = default;
};

class B {
    std::unique_ptr<A> good_a;

    B() : good_a{ std::make_unique<A>(1) } {}
    ~B() = default;
};

int main()
{
    std::vector<B> all;

    B my_b(123);

    all.emplace_back(std::move(my_b));

}

此答案主要针对您似乎遇到的编译错误。好的或坏的做法留给其他人插话。

您的代码有几个错误,但主要错误似乎是您的自定义 B( ) 构造函数禁止默认移动构造函数。如果添加它,您的代码将变得合式。

这是一个完整的工作代码供参考:

#include <memory>
#include <vector>

class A {
private:
    int number;

public:
    void f();
    A(int i) : number{i} {}
    ~A() = default;
};

struct B {
    std::unique_ptr<A> good_a;

    B(int k) : good_a{ std::make_unique<A>(k) } {}

    B(B&& ) = default;
    B& operator=(B&& ) = default; // not needed for the example, but good for completeness
};

int main()
{
    std::vector<B> all;
    B my_b(123);
    all.emplace_back(std::move(my_b));
}

And why wouldn't this work?

你描述的可能有效。

I do not understand why this would not be allowed?

您描述的内容将被允许。

Would I have to create a custom move constructor?

不,这不是必需的,除非您定义了其他特殊成员函数,或者有其他成员(除了唯一指针)已删除或私有移动构造函数。

The unique ptr should be deleted as soon as the object instance is being removed from the vector as there are no references left, right?

成员在超级对象被销毁时被销毁。唯一指针的析构函数调用其拥有的指针上的删除器。

指向对象是否有引用对是否删除没有影响。任何引用已删除对象的内容都将悬空。

Is it bad practice?

您所描述的一般情况不一定有什么特别糟糕的地方,但这取决于确切的细节。

一个潜在的问题是动态分配在某些情况下可能会很昂贵,并且不必要地使用它会不必要地昂贵。因此,您应该有一些理由动态分配指向的对象而不是将它们直接存储为成员。


您的示例中的错误:

  • 您尝试初始化 B(123),但 B 没有接受整数的构造函数。
  • 您试图在 B 的成员函数之外初始化一个 B,但它的构造函数和析构函数具有私有访问权限。
  • 您有用户为 B 声明的析构函数,但没有用户声明移动构造函数或赋值运算符,因此 class 不可移动,这是存储在 [=16= 中的要求].

这是一个不使用不必要的动态分配的固定版本:

struct A {
    int number;
};

struct B {
    A good_a;
};

B my_b{123};
all.push_back(my_b);

请阅读

根据显式声明的内容,隐式定义或删除具有默认实现的相应构造函数。规则描述为 table:

由于您使用了显式定义的析构函数(默认情况下),因此您已禁用(“未声明”)移动构造函数。

所以要修复它,您必须显式定义移动构造函数或删除析构函数的定义:https://godbolt.org/z/dr8KrsTfq