构造函数初始化列表vs昂贵操作
Constructor initializer list vs. expensive operations
考虑一个假设的场景,其中两个类可以默认构造,也可以相互构造,但无论哪种方式都被认为是昂贵的(下面是故意设计的示例):
struct PrivateKey;
struct PublicKey {
PublicKey(); // generate a random public key (1 minute)
PublicKey(const PrivateKey& b); // find a public key corresponding to a private key (1 year)
...members...
};
struct PrivateKey {
PrivateKey(); // generate a random private key (1 minute)
PrivateKey(const PublicKey& a); // find a private key corresponding to a public key (1 year)
...members...
};
(这当然可以浓缩成一个类,但问题的有效性不受影响。假设为了相干性,两者之间不存在对称性
现在有一个结构体保存了这两个实例,并且需要交叉初始化。然而,我们可能需要两个方向,所以初始化列表并不能真正做到这一点(它们不是按照列出的顺序运行,而是按照成员定义的顺序运行,并且这里的顺序不能固定):
struct X {
PublicKey a;
PrivateKey b;
X(int): a(), b(a) { }
X(float): b(), a(b) { } // UB: a(b) happens before b is initialized
};
我当然可以试试:
struct X {
PublicKey a;
PrivateKey b;
X(int): a(), b(a) { }
X(float): a(), b() { a = PublicKey(b); }
};
,但这有多个问题,其中在X
的第二个构造函数中运行PublicKey
的昂贵的默认构造只是为了立即抛出结果,这只是第一个问题。 PublicKey::PublicKey()
可能有副作用。这两种情况仍然可以通过创建一个只向朋友X
公开的廉价私有构造函数来缓解,这将使类处于某种虚拟状态,但会抛出一些引用或常量成员,并且类可能不可移动赋值或不可交换,从而禁止在X::X(float)
的主体上进行任何更改。有没有更好的模式可以遵循?
可以通过使用指向所包含类的指针来避免构造顺序问题,而不是直接嵌入所包含的类,并在构造函数的主体中自己构造所包含的对象。
struct X {
std::unique_ptr<PublicKey> a;
std::unique_ptr<PrivateKey> b;
X(int) {
a = std::make_unique<PublicKey>();
b = std::make_unique<PrivateKey>(*a);
}
X(float) {
b = std::make_unique<PrivateKey>();
a = std::make_unique<PublicKey>(*b);
}
};
如果这些类至少是可移动构造的,那么您应该能够这样做:
struct KeyPair
{
PublicKey a;
PrivateKey b;
KeyPair(std::pair<PublicKey, PrivateKey> &&data) :
a(std::move(data.first)),
b(std::move(data.second))
{}
};
std::pair<PublicKey, PrivateKey> computePublicFirst()
{
PublicKey a;
PrivateKey b(a);
return {std::move(a), std::move(b)};
}
std::pair<PublicKey, PrivateKey> computePrivateFirst()
{
PrivateKey b;
PublicKey a(b);
return {std::move(a), std::move(b)};
}
struct X
{
KeyPair keys;
X(int) : keys(computePublicFirst()) {}
X(float) : keys(computePrivateFirst()) {}
};
没有移动赋值,只有移动构造。
相关文章:
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 重载操作程序时出错>>用于类中的字符串 memebr
- 如何为模板化对象创建模板向量?VS正在投掷C3203
- 数据成员SFINAE的C++17测试:gcc vs clang
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 对字符串进行位操作
- 在for循环中使用auto vs decltype(vec.size())来处理字符串的向量
- 正在VS调试器中监视映射条目
- Confusion: decltype vs std::function
- 将IBM Rhapsody模型集成到VS 2019中
- gmock 设置默认操作 / ON_CALL vs. EXPECT_CALL
- C++类函数返回值 VS 对本地数据进行操作
- 写入和读取操作:使用一个 wrlock 两个 VS 一个 rdlock 读取操作和一个 wrlock 写入操作
- 为什么以下两个程序产生不同的输出?(C++,位操作,VS 2012)
- 构造函数初始化列表vs昂贵操作
- NEON vs Intel SSE -某些操作的等价性
- VS在汇编操作码中嵌入字符串
- 比较交换原子操作vs加载链接/存储条件操作
- 算术与双vs位操作