当依赖项没有复制构造函数或赋值运算符时的 C++ 初始化程序列表
C++ Initializer list when dependencies do not have copy ctor or assignment operator
方法一
我有一些 Foo 类型,它内部包含一个 std::mutex.
class Foo {
std::mutex m_;
};
我又写了一个class吧。 Bar 将 Foo 作为成员和构造函数,如下所示(注意 - 此代码无法编译):
class Bar {
Bar(Foo foo) : foo(foo) {}
...
private:
Foo foo;
};
我的 IDE 抱怨:
Call to implicitly-deleted copy constructor of Foo.
copy constructor of 'Foo' is implicitly deleted because field 'm_' has a deleted copy constructor
方法二
然后我尝试做这样的作业:
class Bar {
Bar(Foo fooIn) { foo = fooIn; }
...
private:
Foo foo;
};
但这也说明:
Object of type 'Foo' cannot be assigned because its copy assignment operator is implicitly deleted
方法 3(使用指针)
我能让它工作的唯一方法是这样的:
class Foo {
private:
std::mutex m_;
};
class Bar {
Bar(std::unique_ptr<Foo> fooIn) : foo(std::move(fooIn)) {}
private:
std::unique_ptr<Foo> foo;
};
我了解智能指针有助于内存管理。但是让我们把这个功能放在一边。
在我上面的例子中,不使用智能指针和使用智能指针的主要区别在于智能指针具有间接性——它指向堆上的一个对象。对吗?
理解这个的正确心智模型是什么?是不是因为 Foo 有一个删除的复制构造函数和删除的复制赋值,我唯一的选择是让它在堆上构造,然后通过间接(通过指针)工作?
对吗?还是我完全离开了?
Is it that because Foo has a deleted copy constructor and deleted copy assignment, my only option is to have it constructed on the heap and then work via indirection (via pointers)?
接近,但不完全是。
因为互斥锁是不可复制的,所以默认情况下 Foo 也是不可复制的。您正在尝试复制,这是不可能的。
使用间接引用存储在别处的 Foo 是可能的。但是 Foo 没有必要拥有动态存储来实现这一点。不可复制性也不意味着需要间接...除非您想防止不可复制性传播到封闭的 class.
互斥量唯一的构造函数是默认构造函数。因此,您可以合理地做的只是默认初始化 Foo。一个最小的例子:
struct Bar {
Foo foo;
// no need to declare the default constructor
// it is generated implicitly
};
Bar bar; // this just works
如果您检查互斥锁的实现方式,您会看到它的复制构造函数和复制赋值运算符被删除,但移动构造函数和移动赋值运算符没有,这就是您的智能指针示例有效的原因。
my only option is to have it constructed on the heap and then work via indirection (via pointers)?
不,这不是唯一的方法。如果您稍微更改第一个示例以使用引用,那也可以正常工作(并且 foo
不是在堆上构建的):
class Foo {
std::mutex m_;
};
class Bar {
Bar(Foo& foo) : foo(foo) {}
private:
Foo& foo;
};
方法一
我有一些 Foo 类型,它内部包含一个 std::mutex.
class Foo {
std::mutex m_;
};
我又写了一个class吧。 Bar 将 Foo 作为成员和构造函数,如下所示(注意 - 此代码无法编译):
class Bar {
Bar(Foo foo) : foo(foo) {}
...
private:
Foo foo;
};
我的 IDE 抱怨:
Call to implicitly-deleted copy constructor of Foo. copy constructor of 'Foo' is implicitly deleted because field 'm_' has a deleted copy constructor
方法二
然后我尝试做这样的作业:
class Bar {
Bar(Foo fooIn) { foo = fooIn; }
...
private:
Foo foo;
};
但这也说明:
Object of type 'Foo' cannot be assigned because its copy assignment operator is implicitly deleted
方法 3(使用指针)
我能让它工作的唯一方法是这样的:
class Foo {
private:
std::mutex m_;
};
class Bar {
Bar(std::unique_ptr<Foo> fooIn) : foo(std::move(fooIn)) {}
private:
std::unique_ptr<Foo> foo;
};
我了解智能指针有助于内存管理。但是让我们把这个功能放在一边。
在我上面的例子中,不使用智能指针和使用智能指针的主要区别在于智能指针具有间接性——它指向堆上的一个对象。对吗?
理解这个的正确心智模型是什么?是不是因为 Foo 有一个删除的复制构造函数和删除的复制赋值,我唯一的选择是让它在堆上构造,然后通过间接(通过指针)工作?
对吗?还是我完全离开了?
Is it that because Foo has a deleted copy constructor and deleted copy assignment, my only option is to have it constructed on the heap and then work via indirection (via pointers)?
接近,但不完全是。
因为互斥锁是不可复制的,所以默认情况下 Foo 也是不可复制的。您正在尝试复制,这是不可能的。
使用间接引用存储在别处的 Foo 是可能的。但是 Foo 没有必要拥有动态存储来实现这一点。不可复制性也不意味着需要间接...除非您想防止不可复制性传播到封闭的 class.
互斥量唯一的构造函数是默认构造函数。因此,您可以合理地做的只是默认初始化 Foo。一个最小的例子:
struct Bar {
Foo foo;
// no need to declare the default constructor
// it is generated implicitly
};
Bar bar; // this just works
如果您检查互斥锁的实现方式,您会看到它的复制构造函数和复制赋值运算符被删除,但移动构造函数和移动赋值运算符没有,这就是您的智能指针示例有效的原因。
my only option is to have it constructed on the heap and then work via indirection (via pointers)?
不,这不是唯一的方法。如果您稍微更改第一个示例以使用引用,那也可以正常工作(并且 foo
不是在堆上构建的):
class Foo {
std::mutex m_;
};
class Bar {
Bar(Foo& foo) : foo(foo) {}
private:
Foo& foo;
};