gpt4 book ai didi

c++ - 类是否应该具有双重破坏的弹性?

转载 作者:太空宇宙 更新时间:2023-11-03 10:23:54 25 4
gpt4 key购买 nike

我遇到这样一种情况,其中并发访问的容器的分配器需要同时调用 placement new 和析构函数。

    template< class U > void destroy(U* p){
p->~U();
}

事实上,我最终可以反复调用破坏。这让我开始思考这样的事情是否应该可行。

   std::vector<int>* p = (std::vector<int>*)malloc(sizeof(std::vector<int>));
::new (*p) std::vector<int>(30);
(*p)[10] = 5;
p->~std::vector<int>();
p->~std::vector<int>();
free(p);

我认为只要 std::vector 的销毁将数据指针设置为 null 或将大小设置为零,并且再次调用时没有双重释放,这就会起作用。

那么,是否应该将意外(或良性)双重破坏等同于一次破坏?

换句话说,销毁应该是幂等操作吗?

(为简单起见,请注意此示例中的析构函数不是虚拟的)

我发现这个问题类似于如何允许稍后销毁移动的类的问题。


一些答案​​将运行时成本作为反对支持双重销毁的理由。有成本,但它们类似于移动物体的成本。换句话说,如果移动成本低,则允许双重销毁成本低(如果 DD 由于其他原因(例如标准)首先不是 UB)。

具体来说:

class dummyvector{
int* ptr;
public:
dummyvector() : ptr(new int[10]){}
dummyvector(dummyvector const& other) = delete; // for simplicity
dummyvector(dummyvector&& other) : ptr(other.ptr){
other.ptr = nullptr; // this makes the moved object unusable (e.g. set) but still destructable
}
dummyvector& operator=(dummyvector const&) = delete; // for simplicity
void set(int val){for(int i = 0; i != 10; ++i) ptr[i]=val;}
int sum(){int ret = 0; for(int i = 0; i != 10; ++i) ret += ptr[i]; return ret;}
~dummyvector(){
delete[] ptr;
ptr = nullptr; // this is the only extra cost for allowing double free (if it was not UB)
// ^^ this line commented would be fine in general but not for double free (not even in principle)
}
};

最佳答案

鉴于销毁意味着对象生命周期的结束,处理双重销毁需要付出代价(使内存处于可重新销毁状态的额外工作)以获得格式良好的代码永远不会遇到的好处。

说双重销毁没问题等同于说释放后使用没问题;当然,在特定情况下允许它的分配器可能会使有缺陷的代码继续工作,但这并不意味着它是一个值得保留在分配器中的功能,如果它会阻止分配器在非病态情况下有效和正确地工作。

如果您曾经处于可能发生双重破坏的位置,那么您可能处于可能存在破坏后使用的位置,现在您必须让类中的每个操作都检查并“处理”(不管是什么意思)在被破坏的实例上被调用的可能性。您已经损害了正常操作以允许滥用,这是一条糟糕的开始之路。

简短版本:不防止双重破坏;在你被双重破坏的那一刻,有问题的代码无论如何都进入了未定义的行为领域,处理它不是你的工作。编写一开始就不会做糟糕事情的代码。

关于c++ - 类是否应该具有双重破坏的弹性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48533939/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com