私有运算符删除会触发GCC和Clang的编译时错误,但不会触发MSVC [英] Private operator delete triggers compile-time error with GCC and Clang but not with MSVC

查看:71
本文介绍了私有运算符删除会触发GCC和Clang的编译时错误,但不会触发MSVC的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

出于这个要求不高的重复的动机,我相信这个问题值得一个新的,标题明确的独立问题.以下代码会触发GCC 8.1.0和Clang 6.0.0的编译错误,但不会触发MSVC 19.00的编译错误:

class X {
   public:
      X() /* noexcept */ { }    
   private:
      static void operator delete(void*) { }
};

int main() { 
    X* x = new X{}; 
}

来自 expr.new :

如果上述对象初始化的任何部分因引发异常而终止,并且可以找到合适的释放函数,则调用释放函数以释放正在构造对象的内存,此后异常继续传播在new-expression的上下文中. 如果找不到明确的匹配释放函数,则传播异常不会导致对象的内存被释放. [注意:分配内存;否则,很可能导致内存泄漏. — 尾注]

实际上,这并不意味着如果找不到匹配的释放函数::operator delete,则应触发编译错误.或者,将其设置为私有只是导致类似但却无法访问的问题?哪些编译器是正确的?

解决方案

这里有两个问题:

  1. 即使operator delete是私人的,如何找到它?

C ++首先尝试在任何地方找到一个名称​​ ;请稍后检查访问保护.
因此,您的operator delete已找到,但无法访问.

  1. 为什么构造器为noexcept时我的operator delete必须可访问?

措辞如果对象初始化的任何部分因引发异常而终止",则表明该段的其余部分由于noexcept而不适用​​.daccess-ods.un.org daccess-ods.un.org

但是,正如"...的任何部分"所建议的那样,在分配与进入构造函数之间(评估初始化程序时)或在退出构造函数之后(销毁初始化程序时)可能存在异常.

考虑

struct Y
{
    Y() {}
    Y(const Y&) { throw "sorry"; }
};

class X {
   public:
      X(Y y) noexcept { }    
   private:
      static void operator delete(void*) { }
};

int main() { 
    Y y;
    X* x = new X{y}; 
}

Y复制构造函数在您输入X的构造函数之前但在分配之后抛出的位置,因此需要释放内存.

所以我认为Visual C ++是错误的(再次).

Motivated by this not very well asked duplicate, I believe the problem deserves a new standalone clearly titled question. The following code triggers a compilation error with GCC 8.1.0 and Clang 6.0.0, but not with MSVC 19.00:

class X {
   public:
      X() /* noexcept */ { }    
   private:
      static void operator delete(void*) { }
};

int main() { 
    X* x = new X{}; 
}

From expr.new:

If any part of the object initialization described above terminates by throwing an exception and a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object was being constructed, after which the exception continues to propagate in the context of the new-expression. If no unambiguous matching deallocation function can be found, propagating the exception does not cause the object's memory to be freed. [ Note: This is appropriate when the called allocation function does not allocate memory; otherwise, it is likely to result in a memory leak. — end note ]

In fact, this does not imply that the compilation error should be triggered if the matching deallocation function ::operator delete cannot be found. Or, does making it private just results in something like can be found but cannot be accessed? Which compilers are right?

解决方案

There are two questions here:

  1. How is operator delete found even though it's private?

C++ first tries to find a name anywhere; checking access protection is a later phase.
Thus, your operator delete is found, but inaccessible.

  1. Why must my operator delete be accessible when the constructor is noexcept?

The wording "If any part of the object initialization [...] terminates by throwing an exception" suggests that the rest of the paragraph doesn't apply because of the noexcept.

However, as suggested by "any part of...", there may be exceptions inbetween the allocation and entering the constructor (while evaluating initialisers), or after exiting the constructor (while destroying initialisers).

Consider

struct Y
{
    Y() {}
    Y(const Y&) { throw "sorry"; }
};

class X {
   public:
      X(Y y) noexcept { }    
   private:
      static void operator delete(void*) { }
};

int main() { 
    Y y;
    X* x = new X{y}; 
}

where the Y copy constructor throws before you enter X's constructor, but after allocation, so the memory needs to be released.

So I think Visual C++ is wrong (again).

这篇关于私有运算符删除会触发GCC和Clang的编译时错误,但不会触发MSVC的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆