c++ - 在联合崩溃程序中分配 std::function
问题描述
我编写了以下类,它存储一个固定值(constant
)或一个函数来获取一个值(get
)。
template <typename T>
class DynamicValue {
private:
bool isConstant;
union {
T constant;
std::function<T()> get;
};
void copy(const DynamicValue& value) {
isConstant = value.isConstant;
if (isConstant) {
constant = value.constant;
} else {
std::cout << "won't overcome next line" << std::endl;
get = value.get;
std::cout << "why!" << std::endl;
}
}
public:
DynamicValue(const T& constant) : isConstant(true), constant(constant){};
template <typename F, typename = std::enable_if_t<std::is_invocable_v<F>>>
DynamicValue(F&& get) : isConstant(false), get(std::forward<F>(get)) {}
DynamicValue(const T* pointer) : DynamicValue([pointer]() { return *pointer; }) {}
DynamicValue(const DynamicValue& value) { copy(value); }
~DynamicValue() {}
DynamicValue& operator=(const DynamicValue& value) {
copy(value);
return *this;
}
operator T() { return isConstant ? constant : get(); }
};
我还编写了以下虚拟类来展示我遇到的问题:
class Object {
private:
DynamicValue<int> num;
public:
Object(DynamicValue<int> num) : num(num) {}
};
问题是当我尝试Object
用一个函数初始化一个(Object b([] { return 1; });
例如)时,程序崩溃了。我已将崩溃范围缩小到get = value.get;
复制功能内的行。我还注意到,如果我离开get
工会,崩溃就不会再发生了。
你可以在这里尝试一个活生生的例子。
为什么会发生这种情况,我该如何解决(保留get
在工会内部)?
解决方案
为了将联合的活动成员更改为非平凡类型/从非平凡类型更改,您必须放置新的构造它/调用它的析构函数:
void copy(const DynamicValue& value) noexcept {
if (isConstant && value.isConstant) {
constant = value.constant;
} else if (!isConstant && !value.isConstant) {
get = value.get;
} else if (value.isConstant) {
get.~function();
new (&constant) T(value.constant);
} else {
constant.~T();
new (&get) std::function<T()>(value.get);
}
isConstant = value.isConstant;
}
请注意,这copy
是noexcept
因为如果放置 new 失败,则无法恢复。如果你想避免这种情况,你需要在你的类中添加一个 valueless-by-exception 状态,它可以被破坏,但没有其他操作是有效的。
此外,由于 的前提条件copy
是您的对象处于有效状态,因此您的复制构造函数必须首先将自身初始化为该constant
状态:
DynamicValue(const DynamicValue& value) : DynamicValue(T{}) { copy(value); }
请注意,这假设它T
是默认可构造的。或者,您可以初始化到get
状态,但这可能效率较低,尤其T
是在微不足道的情况下。
最后,为了防止泄漏,您应该确保您的析构函数将联合置于微不足道的状态:
~DynamicValue() {
if (isConstant)
constant.~T();
else
get.~function();
}
例子。
推荐阅读
- python - Django 无法加载静态文件 - internal-nginx-static 来自 URL
- web - 页面获取不适用,未获取站点地图,允许索引?不适用,在实时测试期间,索引问题,robot.txt 文件被阻止,站点没有任何问题
- c++ - EXC_BAD_ACCESS:使用 std::array 的问题
- c# - 有没有办法为泛型类型对象进行扩展?
- typescript - babel.config.js 的“模块”未定义错误
- python - 使用多个输入时的默认值
- reactjs - 使用 Next Js Link 时更新 React 类组件
- google-cloud-pubsub - 如何检查发布者端的发布子批处理设置是否真的按照配置工作?
- html - 如何在 Wordpress Elementor 中将背景图像设置为全屏宽度
- python - 从导入的数据文件在 Python 中制作密度图