为什么在gcc编译器中,持有派生类引用的基类的std::unique_ptr不会显示警告,而裸指针会显示警告?

33

我有一个基类和派生类的层次结构。基类有一个虚函数,被派生类覆盖。

class Base
{  
public:  
    ~Base();    
    virtual void other_functionality() = 0;  
};

class Derived : public Base
{  
public:  
    ~Derived ();    
    void other_functionality() {//some code};  
};

现在如果我这样做:

int main()
{
Base * P = new Derived ();
delete p;
return 0;
}

出现错误:
删除具有非虚析构函数的多态类类型对象。

但使用 unique_ptr 时,它能够通过而没有警告。

int main()
{
 std::unique_ptr<Base> p;
 p.reset(new Derived ());

return 0;
}

我知道如果使用虚析构函数,裸指针的警告将被解决。 但问题仍然存在-为什么缺少虚析构函数会显示裸指针的问题,而不是unique_ptr。

我知道如果我使用虚拟析构函数,则可以解决裸指针的警告。 但问题仍然存在-为什么没有虚拟析构函数会导致裸指针的问题,而unique_ptr则不会。


2
记录一下,clang 确实会抱怨:https://godbolt.org/z/qEp6Ts - Max Langhof
1
@P.W 我不认为这是重复的。至少,两个问题的答案是不同的。(原问题的答案是“因为标准不要求进行这样的检查”。而这个问题的答案是“因为gcc会抑制系统头文件的警告”)。 - Daniel Langr
1
@DanielLangr:本质上问题似乎是相同的。但是答案并没有直接解释为什么编译器不发出诊断。因此我会重新打开。 - P.W
1
@gauravbharadwaj 这也适用于C++17,并且几乎可以保证在C++20中使用。我认为这个问题现在并不特定于语言的任何特定版本... - Michael Kenzel
1
@gauravbharadwaj 我认为你标记了boost是公平的,那个人的评论非常不恰当。然而,我也认为这个标记是错误的,这是一个纯粹的标准C++问题,你甚至不知道boost的存在就能回答这个问题。 - ypnos
显示剩余6条评论
2个回答

40
首先,如果基类没有虚析构函数,则通过基类指针删除派生对象是未定义行为。编译器不需要诊断未定义行为…
话虽如此,使用std::unique_ptr时,为什么不会出现该警告,很可能是因为GCC不报告系统头文件中可能出现的警告

20

我找不到链接,但我在GCC错误数据库的讨论中看到了这个问题。

警告是在实际的delete表达式上发出的。对于unique_ptrdelete是在系统头文件中调用的。

根据该错误报告中的讨论,实现C++系统库需要各种妥协,从而导致各种警告。因此,警告被限制在系统头文件中。这就是您不会看到期望的警告的原因。

更新:直接从消息来源处获得:

https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html

操作系统和运行时库的接口声明头文件通常无法以严格符合C语言规范的方式编写。因此,GCC会对系统头文件中发现的代码进行特殊处理。在GCC处理系统头文件时,除了由“#warning”生成的警告之外,所有警告都会被抑制。请参见诊断。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接