从函数参数抛出异常

Ale*_*sky 5 c++ c++20

下面的代码会产生内存泄漏吗?

#include <utility>
#include <stdexcept>

struct A {};

struct B {
    B() {
        throw std::runtime_error("");
    }
};

template <class T>
class MyPtr {
public:
    MyPtr(T* p) : m_p(p) {}

    MyPtr(MyPtr&& other) : m_p(other.m_p) {
        other.m_p = nullptr;
    }

    ~MyPtr() {
        delete m_p;
    }

private:
    T* m_p;
};

class Foo {
public:
    Foo(MyPtr<A> a, MyPtr<B> b) : m_a(std::move(a)), m_b(std::move(b)) {}

private:
    MyPtr<A> m_a;
    MyPtr<B> m_b;
};

int main() {
    try {
        Foo foo(new A(), new B());
    }
    catch (const std::exception&) {
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

之间有区别吗

Foo foo(new A(), new B());
Run Code Online (Sandbox Code Playgroud)

和

Foo foo(MyPtr(new A()), MyPtr(new B()));
Run Code Online (Sandbox Code Playgroud)

?

lor*_*rro 5

在现代 C++ 版本中,求值顺序基于顺序前和顺序后。这意味着,将会发生以下情况:

  • 以任何非重叠顺序:new A(), new B()- 为 和 分配内存A,并B运行构造函数(这些不能交错)
  • 由于B有一个 ctor,因此该 ctor 会运行(分配后排序)
  • B的throw演员
  • 由于B的 ctor 没有完成,因此new 构造时B分配的内存将被释放,而不调用 dtor。

请注意,对 的 ctor 的调用Foo将在上述之后进行排序,因此不会到达它。

因此,B不被泄露。但是,函数参数可以以任何不重叠的方式排序,因此A可能会也可能不会泄漏。从理论上讲,这可能会因运行而异。

如果你这样做:Foo foo(MyPtr(new A()), MyPtr(new B()));,那么你会立即将指针封装到之后的智能指针new,这样就不会泄漏。

另外,值得一提的是,虽然 for 的内存B 被B释放,但在的 ctor 中分​​配且未释放的任何内存throw仍然可能会泄漏。在本示例中没有这样的分配,但在实际代码中可能会发生。唯一释放的内存是正在构造的整个对象的内存。