我可以在构造函数的主体中转发构造吗?
Can I forward construction in the body of a constructor?
让我们考虑一下,在执行类S
的构造函数时,似乎可以使用另一个构造函数构造S
。一种解决方案可能是在this
上新建一个放置位置以重用存储:
struct S{
unsigned int j; //no const neither reference non static members
S(unsigned int i){/*...*/}
S(int i){
if (i>=0) {
new (this) S(static_cast<unsigned int>(i));
return;}
/*...*/
}
};
int i=10;
S x{i};//is it UB?
存储重用在 [basic.life] 中定义。我不知道在构造函数执行期间(重新(使用存储时如何阅读本节。
在这种情况下,标准完全未指定,我找不到相关的 CWG 问题。
就其本身而言,您的新展示位置不是 UB。毕竟,您拥有没有对象的存储,因此您可以直接在其中构造一个对象。正如您正确所说,第一个对象的生存期尚未开始。
但现在的问题是:原始对象会发生什么变化?因为通常情况下,构造函数只在没有对象的存储上调用,构造函数的结束标志着对象的生存期的开始。但是现在已经有另一个对象了。新对象是否被销毁?它没有效果吗?
该标准在[class.cdtor]中缺少一个段落,该段落说明了如果在正在构建和销毁的对象存储中创建新对象时会发生什么。
你甚至可以构建更奇怪的代码:
struct X {
X *object;
int var;
X() : object(new (this) X(4)), var(5) {} // ?!?
X(int x) : var(x) {}
} x;
是 UB 吗?
不,不是。[basic.life]/5
说:
程序可以通过重用对象占用的存储或使用非平凡析构函数显式调用类类型的对象的析构函数来结束任何对象的生存期。对于具有非平凡析构函数的类类型的对象,程序不需要在重用或释放对象占用的存储之前显式调用析构函数;但是,如果没有显式调用析构函数,或者未使用 delete-expression 来释放存储,则不应隐式调用析构函数,并且依赖于析构函数产生的副作用的任何程序都具有未定义的行为。
强调与您的类相关的部分,该部分具有微不足道的析构函数。关于具体的new (this) T;
形式,我在[class.cdtor]
和[class.dtor]
中都没有发现这条规则的例外。
- 在按值调用 (c++) 中转发构造函数参数
- 完美的转发和构造函数
- 我可以在构造函数的主体中转发构造吗?
- 通过类型别名从构造函数转发模板推导
- 如何通过可变参数模板将多个构造函数参数转发到数组初始值设定项列表?
- 完美的转发构造函数和已删除的构造函数
- 如何构造一个 std::variant 类型对象,其自身 Templated 和构造函数转发参数
- 使用完美转发的模板转换构造函数
- 禁用 std::optional的转发构造函数
- 通过转发构造函数参数来构建基于可变参数模板的 mixin
- 为什么我们应该为initializer_list的情况过多载荷转发构造函数
- 在类层次结构中,完美的转发构造函数和复制构造函数之间的冲突
- 完美的转发功能与完美的转发构造函数
- 转发构造函数调用基类的复制构造函数2次
- 使用declard和参数转发构造函数隐式复制结构
- 临时寿命和完美的转发构造函数
- 如何为类似元组的可变类创建一个完美的转发构造函数
- 复制构造函数和转发构造函数之间存在冲突
- 单例、奇怪的重复模板模式和转发构造函数参数
- 通过接口转发构造函数参数