【问题标题】:Why does passing an anonymous stack-allocated array to a unique_ptr not cause a segfault? [duplicate]为什么将匿名堆栈分配的数组传递给 unique_ptr 不会导致段错误? [复制]
【发布时间】:2020-12-19 21:45:08
【问题描述】:

当我意识到以下代码编译并成功运行时,我正在通过重新创建基本的std::unique_ptr 来尝试模板特化:

namespace not_std {

template<typename T>
class unique_ptr
{
public:
    unique_ptr(T *pointer)
        : pointer_(pointer)
    { }

    ~unique_ptr()
    {
        delete pointer_;
    }

private:
    T *pointer_;
};

template<typename T>
class unique_ptr<T[]>
{
public:
    unique_ptr(T *pointer)
        : pointer_(pointer)
    { }

    ~unique_ptr()
    {
        delete[] pointer_;
    }

private:
    T *pointer_;
};

} // namespace not_std

int main()
{
    not_std::unique_ptr<char[]> buffer(char[64]);
}

请注意,我不是在寻找有关实现的反馈,因此我已经删除了类定义中不相关的部分。

起初我以为这是我的实现中的一个错误,但事实证明,即使使用标准实现,这段代码也能编译并运行。

我认为这段代码会中断,因为char[64] 在我看来就像一个匿名堆栈分配数组。如果是这种情况,那么它的生命周期会在 std::unique_ptr 的构造函数返回时结束。那么析构函数不会在现在也超出范围的堆栈分配内存上调用delete[] 吗?

也许我误解了到底发生了什么,因为我以前从未见过这种语法,其中数组T[N] 直接作为参数传递。

感谢任何澄清/解释。

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    就在我即将发布这个问题时,我发现了问题:

    1. unique_ptr&lt;char[]&gt; buffer(char[64]) 实际上声明了一个名为buffer 的函数,该函数将char[64] 作为未命名参数并返回unique_ptr&lt;char[]&gt;。所以这实际上是@xaxxon 指出的最令人头疼的解析实例。

    2. 数组不能用这种语法初始化:char[64]

    3. 传递临时数组不符合标准,但可以使用 clang。相反,它看起来像unique_ptr&lt;char[]&gt; buffer((char[64]){ }),并且确实会导致段错误,正如预期的那样。

    请注意,这并不是建议传递堆栈分配的数组是一个好主意。

    认为让其他人知道是值得的,这样他们就不会重蹈我的覆辙……

    【讨论】:

    • 这仍然被破坏,因为你的字符数组在该行完成后立即被销毁,但是你的 unique_ptr 将在其范围结束时尝试删除它,这就是双重删除 UB。您应该使用new 分配字符数组或make_unique
    • @xaxxon 他们意识到了这个问题,他们正试图通过这个 UB 产生可观察到的问题。
    • @ThatBantIsClass 我对答案投了反对票,因为它的重要部分是错误的。例如,第 3 部分存在多个问题。但通常也是因为问题和答案与其他更好的答案重复。
    • @ThatBantIsClass 您正在删除一个未更新的对象。你的推断是正确的,这将是一个错误。但是,您期望它出现段错误是不正确的。该错误导致未定义的行为,它可能会出现段错误,它可能不会产生可观察到的问题,它可能会破坏不相关的对象,或者它可能会做任何其他想象的事情。您不应期望错误总是导致明显甚至可检测到的事件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-22
    • 2021-11-06
    • 1970-01-01
    • 2019-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多