Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/115.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;:重载多态单例类上的delete_C++_Memory Management_Singleton_Operator Overloading_Dynamic Memory Allocation - Fatal编程技术网

C++ C++;:重载多态单例类上的delete

C++ C++;:重载多态单例类上的delete,c++,memory-management,singleton,operator-overloading,dynamic-memory-allocation,C++,Memory Management,Singleton,Operator Overloading,Dynamic Memory Allocation,假设我有以下几点: struct Base { virtual ~Base() noexcept = default; ... }; struct Singleton : public Base { void* operator new(size_t sz) noexcept { return instance(); } void operator delete(void* ptr) noexcept { // the body is supposed to b

假设我有以下几点:

struct Base {
  virtual ~Base() noexcept = default;
  ...
};

struct Singleton
    : public Base {
  void* operator new(size_t sz) noexcept { return instance(); }
  void operator delete(void* ptr) noexcept {
    // the body is supposed to be empty since new() doesn't allocate
    ++delete_count;
  }
  static Singleton* instance() noexcept {
    static Singleton kInstance;
    return &kInstance;
  }
  ...
};
(我使用这样的单例类来减少多态容器类中的开销,例如
std::vector
,特别是当容器中出现多个时。)

我很惊讶以下代码会崩溃:

有趣的是,如果我使
Singleton
类非多态,即从
Base
中删除虚拟析构函数,那么一切都可以正常工作(即使我通过添加类成员使
Base
类非空)

有人能解释为什么会发生这种情况以及如何解决它吗

编辑:似乎要将
单例::删除
更改为:

void operator delete(void* ptr) noexcept {
  ::new(ptr) Singleton;  // re-initialize using placement new
  ++delete_count;
}

至少在GCC 4.8.1上可以运行,代码在GCC(4.9)和Clang中都运行良好GCC4.8.2失败。VC++2013也失败

这是一本书


您使用的编译器(当然还有版本)是什么?

我想这就是g++如何管理其内部状态

我发现这段代码在clang中正确编译和运行,但在gcc中失败。原因是,在第一次删除时,它调用定义的类。但对于第二个电话,它需要全球电话


为了解决这个问题,我建议将分配和解除分配移动到您正在调用的未定义行为的基类。原因如下

除非要删除的指针为null,否则delete表达式始终调用析构函数。引用C++11标准§5.3.5/6

如果删除表达式的操作数值不是空指针值,则删除表达式将 为要删除的对象或数组元素调用析构函数(如果有)

即使delete表达式像这里一样调用用户定义的释放函数,也会发生这种情况

如果对象具有非平凡的析构函数,则对同一对象调用两次析构函数将调用未定义的行为。这要归功于§12.4/15

一旦为对象调用析构函数,该对象就不再存在;如果 为生存期已结束的对象调用析构函数(3.8)

和§3.8

。。。类型为
T
的对象的生存期在以下情况下结束:

-如果
T
是具有非平凡析构函数(12.4)的类类型,则析构函数调用将启动,或者


但是,如果基类中的虚拟析构函数被删除,那么
单例
的析构函数将变得微不足道(参见§12.4/5)。在这种情况下,行为根据标准进行了明确定义。(从某种意义上说,这是因为平凡的析构函数不是ops,而非平凡的析构函数实际上修改VPTR等。)

您的方法重载
new()
delete
,并声明拥有多个这样的单例是非常奇怪的。可能也是相关的:问题实际上是派生类中重写的操作符
delete
是否被父类识别。如果不是,则由于父类
Base
调用其默认析构函数的实现,程序具有实现定义的行为(可能是UB,但不确定)。有标准的人应该对此发表评论。VisualStudio2013在
deleteS2上逐渐消失
似乎正在调用未被重写的
析构函数。警告:我必须删除<代码> >除了代码> >代码>默认>代码>指定符,用VS 2013编译。检查GCC 4.82和它失败。GCC 4.8-1(Ubuntu 4.81-2Ubuntu1~ 12.04),你是说这是GCC中的一个bug,还是我的例子是未定义行为(根据C++标准)?我也不太明白为什么只有在类是多态的情况下,second
delete
才会导致基类
的释放
的主体删除
使行为定义?@leden是的,我认为这使其定义明确。不要引用我的话,但我的补丁看起来不是线程安全的,是吗?例如,考虑使用单线程的线程,而另一个调用“代码>删除< /代码>……@莱登,这是真的。我真的会在这里建议一个不同的设计。我不确定您是否正在使用
new
delete
它们是要使用的。此外,我认为阅读您的代码的人会发现它非常混乱。因为OP使用的是C++11,所以singleton的简单静态变量版本保证是线程安全的。
void operator delete(void* ptr) noexcept {
  ::new(ptr) Singleton;  // re-initialize using placement new
  ++delete_count;
}