我有一个不太理想的情况,即类返回对父对象生命周期后不应访问的对象的句柄引用。改变下面的模式以帮助防御性编码的最佳方法是什么?
// 'A<T>' is a thin factory-style utility class with asynchronous consumers.
template <typename T>
struct A {
A() : h_(*(new T())) { /* ... */ }
~A() { /* h_ deleted or ownership passed elsewhere */ }
// What's the best way to indicate that these handles shouldn't be used after
// the destructions of the A instances?
T &handle() { return h_; }
private
T &h_;
};
struct B { /* ... */ };
int main() {
B *b1{nullptr};
{
A<B> a;
// Is there a good way to trigger detection that the reference is bound to
// a variable which will outlive its 'valid' local lifetime?
b1 = &a.handle();
B &b2(a.handle()); // this is reasonable though
b1->ok_action();
b2.also_alright();
}
b1->uh_oh();
}
我知道你无法真正阻止C ++用户做出大多数不安全的事情,但如果我至少能够在琐碎的意外使用中产生警告,那么这将是我想要实现的大部分内容。 / p>
答案 0 :(得分:1)
我冒昧地对你的情况作出一些假设:
A
由用户自行决定生成的动态分配对象。A
超出范围的位置传递,因此A
不能用作强制网关。A
时必须销毁句柄指向的数据,因此无法将自动垃圾收集应用于句柄。考虑到这一点,这是一个可能的解决方案:
在A
的构造函数中,分配某种信号对象S
,它在A
被销毁时设置。使用S
处理shared_ptr
。让A::handle
返回自定义句柄类H
,其中包含B
句柄和shared_ptr
到S
。在H
中创建一个解除引用运算符,用于验证A
是否仍然有效(S
未设置),或引发异常。当所有句柄过期时,S
将自动销毁。
答案 1 :(得分:0)
你想让对象A产生另一个B类对象,让某人使用它,然后确保在A之前销毁B?
而不是返回B的实例,是否可以在A上定义一个获取B的方法,然后将其传递给某种委托(虚方法,仿函数,lambda函数)?这样,用户函数嵌套在对A方法上的方法的调用中,因此在用户代码完成任何操作之前,A在逻辑上不可能被销毁。
例如:
class A
{
public:
template <typename Functor>
void DoSomethingWithAnInstanceOfB(const char* whichB, Functor f)
{
B& bref = InternalLookupB(whichB);
f(bref);
}
};
这会查找正确的B实例,然后将其传递给任意仿函数。仿函数可以做任何想做的事情,但必须在DoSomethingWithAnInstanceOfB()返回之前返回,因此保证A的生命周期至少与B一样长。