对C++中成员对象构造的更多控制
More control over construction of member objects in C++
我有几个类,在这些类中,我需要对成员构造进行比初始化列表更多的控制。
在一个类中,如果原始构造抛出,我需要能够重试具有不同参数的成员的构造。
在第二个类中,我需要将成员对象的地址传递给另一个函数,该函数将依次调用构造函数(通过placementnew)。这里的问题是这个函数是一个黑盒,我不知道它会传递给构造函数什么。
在这两种情况下,都要求成员对象保持在包含对象中,而不是动态分配。
实现这一目标的最佳方法是什么?
编辑
我注意到一个问题"是否可以将成员初始化推迟到构造函数主体?",该问题建议boost::optional。这并没有完全解决我的问题,原因有几个。首先,我不想延迟初始化,只想对它有更多的控制。其次,boost::optional存储一个额外的bool来指示对象是否初始化,这在我的情况下是不需要的。然而,它确实让我思考,我想出了我在下面发布的解决方案。
不能仅通过构造函数"重试"构造。您可以使用try/catch吞下/处理构造函数内引起的异常,如果构造函数内的代码失败,则可以继续填充对象(使用简单的赋值)。
如果初始化列表抛出,则表示您。。。搞砸了?不过,初始化列表中不应该抛出任何内容。它是在你的构造函数主体之前执行的,你不能控制其中抛出的异常
如果您确实需要使用不同的参数重试构造,请将构造封装在工厂函数中,该函数可以捕获异常并在收到异常时尝试不同的选项。
继续…当你调用构造函数时,你就调用了构造函数。构造函数本身根据是否使用动态分配机制(主要是新的)在堆或堆栈上创建对象。您不能在构造函数主体本身内决定在其他地方声明对象,因为已经做出了决定。当你调用new时,你必须直接使用placementnew来实现这一点。
将构造和初始化过程分开。我知道这听起来可能很奇怪,但在初始化列表中构造基本对象,然后尝试/catch用分离的init()方法在构造函数的主体中用不同的参数集初始化它。
我最终创建了以下类:
#include <type_traits> // Or <boost/type_traits.hpp>
template <typename Ty>
class manually_constructed
{
public:
template <typename T>
manually_constructed(T construct_func) {
construct_func(static_cast<Ty*>(static_cast<void*>(&data)));
}
~manually_constructed() {
static_cast<Ty*>(static_cast<void*>(&data))->~Ty();
}
Ty& operator*() {
return *static_cast<Ty*>(static_cast<void*>(&data));
}
Ty* operator->() {
return static_cast<Ty*>(static_cast<void*>(&data));
}
private:
// Replace 'std' with 'boost' if your standard library doesn't support
// type_traits, yet.
std::aligned_storage<sizeof(Ty), std::alignment_of<Ty>::value>::type data;
};
然后,在我的类中,我可以有一个成员,如manually_constructed<OtherClass> object
和一个私有静态方法,如:
static void construct_object(OtherClass *p) {
try {
new(p) OtherClass(/* Risky arguments */);
} catch(...) {
new(p) OtherClass(/* Fallback arguments */);
}
}
最后,在我的初始值设定项列表中,我可以有object(construct_object)
。
有了这个解决方案,所有成员对象都存储在包含对象中,没有额外的空间开销,所有的成员对象都按照正确的顺序构建,手动构建的对象将自动销毁。
- 控制允许动态运行c++的并发操作数
- 从控制台中删除最后打印的元素
- 是否可以使用if constexpr删除控制流语句
- 无法在windows控制台中为C++程序提供必要的输入
- 控制到达非空函数clang(-Wreturn-type)的末尾
- 查找 GCD:并非所有控制路径都返回值
- 通过 API 控制 DJI 相机
- 禁止在控制台上记录谷神星
- 是否可以使用一个类来控制 C++ 中另一个类的对象?(阿杜伊诺)
- 如何删除列出的"QGraphicsPathItem"对象以控制进程内存使用情况?
- 我在 C++ 代码中遇到错误警告:控制到达非空函数 [-Wreturn 类型] 的末尾
- C++ Python 模块在 Blender 中崩溃,但在 Python 控制台中不会崩溃
- wx通用目录控制错误"wxTheFileIconsTable was nullptr"
- main() 中的 std::cout 在调试期间不会在调试控制台中打印任何内容
- Cython通过浮点数的最快方式,用于高频控制回路
- 用户控制从 c++ 到 java 脚本的 Webassembly 访问调用
- C ++,如何从控制台中输入的字符串中删除字母?
- 如何从单独的线程控制 SFML 窗口?
- 如何防止 Windows 控制台上的回车键自动滚动
- 我们能否在stm32f中使用硬件定时器控制两个独立的进程