C++ 为什么这不是C++;?

C++ 为什么这不是C++;?,c++,memory-leaks,valgrind,undefined-behavior,unique-ptr,C++,Memory Leaks,Valgrind,Undefined Behavior,Unique Ptr,几个月前,我问了一个问题,我在哪里问过为什么会有内存泄漏。显然,我忘了一个虚拟析构函数 现在我很难理解为什么这不是内存泄漏: #include <iostream> #include <vector> #include <memory> using namespace std; class Base{ public: explicit Base(double a){ a_ = a; } virtual void f

几个月前,我问了一个问题,我在哪里问过为什么会有内存泄漏。显然,我忘了一个虚拟析构函数

现在我很难理解为什么这不是内存泄漏:

#include <iostream>
#include <vector>
#include <memory>


using namespace std;

class Base{
public:
    explicit Base(double a){
        a_ = a;
    }
    virtual void fun(){
        cout << "Base " << a_ << endl;
    }

protected:
    double a_;
};


class Derived : public Base{
public:
    Derived(double a, double b): Base(a), b_{b}{
    }
    void fun() override{
        cout << "Derived " << a_ << endl;
    }
private:
    double b_;
};



int main() {

    vector<unique_ptr<Base> > m;

    for(int i=0; i<10; ++i){
        if(i%2 == 0){
            m.emplace_back(make_unique<Base>(i));
        }else{
            m.emplace_back(make_unique<Derived>(i, 2*i));
        }
    }

    for(const auto &any:m){
        any->fun();
    }

    return 0;
}
#包括
#包括
#包括
使用名称空间std;
阶级基础{
公众:
显式基(双a){
a=a;
}
虚拟虚空乐趣(){

cout如果
b
对象由于未定义的行为而具有资源(内存、网络…),则会出现内存泄漏

在这里,很偶然,派生的析构函数没有做任何事情,并且对象的内存被正确释放(这次)。但是,除了内置的/普通的可破坏类型之外的任何东西都可能触发内存泄漏(例如,我建议您尝试大小为10的
向量


顺便说一句,
o
未被使用?

当基类没有虚拟析构函数时,通过多态指针删除对象是未定义的行为

未定义的行为可能意味着您的代码泄漏内存、崩溃或工作正常

在这种情况下,运行库可能为您的对象分配了一个内存块,并且能够正确删除该内存块,即使它被其他类型的指针指向。这可能适用于大多数运行时,但没有保证。例如,当使用
malloc()
free()时
您不需要将
malloc()
的大小提供给
free()
,这里也发生了同样的情况


如果您在<代码>派生< /代码>中定义析构函数,您将看到它没有被调用。

< Stime>它不会泄漏内存,因为C++的实现方式是如何运行的,但它是未定义的行为,应该修复它。

在这种情况下不是内存泄漏,因为

  • 使用
    新建
    进行分配:

    template unique\u ptr make_unique(Args&&…Args);
    […]
    返回:
    unique\ptr(新T(标准::转发

  • 使用使用
    运算符delete
    的取消分配

  • 从内存泄漏的角度来看,类型不同并不重要,因为
    delete
    仍将使用指向
    new
    分配的对象的指针调用

    如果
    派生的
    没有一个微不足道的析构函数,那么它也将是一个内存泄漏。例如,如果它持有一个
    std::vector
    ,那么
    vector
    的析构函数将被
    ~派生的
    调用。如果它没有被调用,那么
    vector
    的存储将(可检测)泄漏

    另见:

    但是,所有这些都是C++标准的未定义行为,所以理论上它可以随时停止工作。 在单个对象删除表达式中,如果要删除的对象的静态类型与其动态类型和选定的解除分配函数不同(请参见下文)不是销毁运算符delete,静态类型应为要删除对象的动态类型的基类,静态类型应具有虚拟析构函数或行为未定义


    我认为UB不能可靠地导致内存泄漏。除了内置类型之外,还有许多类型可以被破坏。@这很公平。这就是为什么我在第一句话中提到了资源,但后来不够清楚。可能有兴趣知道
    std::shared\u ptr
    将捕获该类型,并调用正确的析构函数。使用
    std::shared_ptr
    而不是
    std::unique_ptr
    会有额外的开销。但是,为了捕获意图,确实应该使用正确的智能指针。使用“错误”指针来捕获类型,所有避免使析构函数虚拟的操作都是错误的(imo)。