从对象成员函数内部删除操作的技术 /设计模式
Techniques / design patterns for postponed delete action from inside of object member function?
说我会陷入我知道要删除的对象的情况 - 当我执行该对象的成员函数的代码一部分时。换句话说,函数返回后,我希望对象被破坏。是否存在适合这种情况的技术或设计模式?我猜想试图从任何对象内部调用破坏者是不安全的(甚至允许的吗?(
回答解释了为什么这是一个坏主意以及如何做到这一点也将受到欢迎。
我认为您想要一个自我包含的对象。
这可以使用具有强参考的"保持"本身的对象实现(C 中的强引用称为shared_ptr
,这是smart pointers
。
#include <iostream>
#include <chrono>
#include <memory>
#include <thread>
using namespace std;
class LengthyOperation {
private:
// Just a marker, for debugging, to differentiated between objects, and to indicate
// a released object if illogical value (or if run under Valgrind / AddressSanitizer)
int i;
// Privatise the constructor, so it can't be constructed without the static factory method.
LengthyOperation(): i(0) {}
LengthyOperation(int i): i(i) {}
// The "Holder", a reference to "this".
weak_ptr<LengthyOperation> holder;
public:
int getId() {
return i;
}
void executeTheOperation() {
// Strongify the weak "holder" reference
// So that no-one would release the object without ending of this function
shared_ptr<LengthyOperation> strongHolder = holder.lock();
// Simulate a "lengthy" operation, by pausing this thread for 1 second
std::this_thread::sleep_for(std::chrono::seconds(1));
cout << "Operation " << i << " ends" << "n";
// Remove the reference to "this" in the holder.
holder.reset();
// Now, the "strong" reference which was temporary created (strongHolder)
// is removed when the scope ends. So that if it is held somewhere
// else, it will not be released until all other holders release it.
// Make sure you will NOT need it again here, because the object
// may be released from memory.
}
~LengthyOperation() {
cout << "Object with id: " << i << " Will destruct now" << "n";
}
static shared_ptr<LengthyOperation> factory(int i = 0) {
shared_ptr<LengthyOperation> ret = shared_ptr<LengthyOperation>(new LengthyOperation(i));
// Make the weak pointer "holder", hold a reference to "this"
ret->holder = ret;
return ret;
}
};
int main() {
thread thr1([](){
weak_ptr<LengthyOperation> operation1Weak;
{
shared_ptr<LengthyOperation> operation1 = LengthyOperation::factory(3);
operation1Weak = operation1;
operation1->executeTheOperation();
cout << "Still there is a strong reference: it refers to object with id "
<< operation1->getId() << "n";
cout << "Releasing the strong reference" << "n";
}
cout << "No strong reference: it is "
<< (operation1Weak.expired() ? "invalid" : "valid") << "n";
});
// Wait for a relative long time, to give chance for all threads to end
// One could use "join" as a better approach.
std::this_thread::sleep_for(std::chrono::seconds(2));
// Detach the thread to avoid crashes
thr1.detach();
thread thr2([](){
// Make an operation, an execute it directly without putting any strong reference to
LengthyOperation::factory(5)->executeTheOperation();
});
std::this_thread::sleep_for(std::chrono::seconds(2));
thr2.detach();
thread thr3([](){
// Try to create the object, without executing the operation, to see what
// weakening the "holder" pointer have done.
weak_ptr<LengthyOperation> oper = LengthyOperation::factory(1);
cout << "The weak non-called is " << (oper.expired() ? "expired" : "valid") << "n";
});
std::this_thread::sleep_for(std::chrono::seconds(1));
thr3.detach();
return 0;
}
这就像在executeTheOperation
中调用"删除",但是通过确保没有其他对象需要它来更安全。
也使用RAII也更好,但这将责任放在"呼叫者"的手上。谁实例化对象,必须释放它。
(在评论中说,强烈的"持有人"参考会导致内存泄漏,如果您不调用executeTheOperation
,则该答案将导致内存泄漏正确地(
您所描述的是资源获取的全部基础是初始化(简称RAII(。简而言之,处理程序对象将保持并拥有您分配的内存,并且该保存的内存与持有人的寿命相关。这意味着当持有人对象消失时,其携带的资源也会被正确销毁。
以下一个例子:
class Class { /* definition */ };
int doOperation(/* arguments */) {
// code
// this 'smart pointer' contains an object of type Class
// you create an object of type Class via dynamic allocation and then it is stored within the ptr object
// this will hold the memory until the end of the function
std::unique_ptr<Class> ptr = std::make_unique<Class>(/*arguments to pass to the object*/);
// use ptr
// assign a return value to returnValue
return returnValue;
// as the function ends, the object ptr is automatically destroyed that in turn will
// automatically delete the memory of object Class it held
}
这种使用std::unique_ptr
是RAII模式的一个示例。其他智能指针,例如std::shared_ptr
,也实现了此模式。
相关文章:
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 资源管理设计模式
- 用于在回调中调用解析器的设计模式
- 设计帮助 - 为不同类型的消息处理通用接口的设计模式
- 在这种情况下我应该使用哪种设计模式
- C++中物体改变识别的设计模式?
- 确保所有构造函数调用相同的函数 c++ 设计模式
- 需要实例化不同类/对象并在启动时确定的硬件插槽的设计模式
- 设计模式,以避免不必要地添加抽象函数以适应新功能
- 工厂设计模式优化
- 使用C++模板的数据映射器设计模式
- 为什么以及如何使用原型设计模式
- 具有多个继承共享一个资源的对象 - 寻找良好的设计模式
- 在C++中创建观察器设计模式的好方法
- 现代C++在多大程度上消除了对设计模式的需求?
- 对于存储另一个类所需信息的类,例如其构造,是否有设计模式?
- 下面抽象工厂设计模式的实现是正确的吗
- sql记录集函数的状态设计模式
- 是否有可以处理方法调用依赖关系的设计模式?
- 从对象成员函数内部删除操作的技术 /设计模式