构造函数初始值设定项列表中的共享参数

Shared argument in constructor initializer list

本文关键字:列表 共享 参数 构造函数      更新时间:2023-10-16

我有这样的类:

class A
{
public:
    A(std::shared_ptr<SomeClass> p);
private:
    std::shared_ptr<SomeClass> _p;
};
class B
{
public:
    B(std::shared_ptr<SomeClass> p);
private:
    std::shared_ptr<SomeClass> _p;
};
class Foo
{
public:
    Foo();
private:
    A _a;
    B _b;
};

来自AB的两个构造函数参数共享相同的指针引用shared_ptr。在这种情况下:

  • 初始化Foo的最佳方式是什么?

  • 是否仍然可以在Foo的构造函数中使用初始化列表?

我很困惑,因为两个类都需要相同的shared_ptr实例,所以我必须将指针存储在某个地方,而我认为这在初始化列表中是不可能的。

此外,如果初始化发生在构造函数的主体中,则意味着AB都应该有move构造函数,对吗?因为我必须做这样的事情:

Foo::Foo() //: Cannot use initializer list
{
    auto ptr = std::make_shared<SomeClass>(SomeClass());
    _a = A(ptr);
    _b = B(ptr);
}

实际上,我想到了一个更好的解决方案。创建shared_ptr,然后委托给一个私有构造函数,该构造函数将使用它来构造_a_b。(感谢Zan Lynx建议使用函数参数作为临时存储。)

class Foo {
public:
    Foo(): Foo(std::make_shared<SomeClass>()) {}
private:
    Foo(std::shared_ptr<SomeClass> ptr): _a(ptr), _b(ptr) {}
    A _a;
    B _b;
};

您不能初始化构造函数主体中的成员。当主体开始执行时,成员必须已经初始化。因此,如果您尝试这样做,成员将是默认构造的,然后您将只分配给它们。AB没有默认构造函数,因此不会编译。

如果你能负担得起尺寸的增加,那么让shared_ptr也成为Foo的成员并使用它。

class Foo {
public:
    Foo(): _ptr(std::make_shared<SomeClass>()), _a(_ptr), _b(_ptr) {}
private:
    std::shared_ptr<SomeClass> _ptr;
    A _a;
    B _b;
};

考虑到您定义类的方式(即无法访问内部shared_ptr),我认为您的解决方案很好。但请注意,AB将需要默认构造函数。这就是在您进入构造函数主体之前初始化它们的方式。

此外,一旦您进入构造函数主体,您将执行赋值。因此AB都需要一个赋值运算符。

此外,我觉得将std::shared_ptr作为引用传递到函数(包括构造函数)中是一种很好的做法。