gcc12 警告数组类型的shared_ptr 释放后使用

问题描述 投票:0回答:1

将我的 gcc 编译器更新到 gcc12.x 版本时,我遇到了一些新警告。

考虑这段代码:

#include <memory>

struct Test
{
    inline static int i = 0;
    Test() { ++i; }
    ~Test() { --i; }
};

struct MHeap
{
    template<typename T>
    void manage() 
    {
        using Td = std::remove_extent_t<T>;
        std::shared_ptr<T> ptr(new T(), std::default_delete<Td[]>{});
    }
};

int main()
{
    MHeap mem;
    mem.manage<Test[3]>();
}

$ g++ -O2 -Wall main.cpp

错误:

In member function 'void MHeap::manage() [with T = Test [3]]',
    inlined from 'int main()' at <source>:24:25:
<source>:17:32: warning: pointer used after 'void operator delete [](void*, std::size_t)' [-Wuse-after-free]
   17 |         std::shared_ptr<T> ptr(new T(), std::default_delete<Td[]>{});
      |                                ^~~~~~~
In file included from /opt/compiler-explorer/gcc-12.3.0/include/c++/12.3.0/memory:75,
                 from <source>:2:
In member function 'typename std::enable_if<std::is_convertible<_Up (*)[], _Tp (*)[]>::value>::type std::default_delete<_Tp []>::operator()(_Up*) const [with _Up = Test; _Tp = Test]',
    inlined from 'std::__shared_count<_Lp>::__shared_count(_Ptr, _Deleter, _Alloc) [with _Ptr = Test*; _Deleter = std::default_delete<Test []>; _Alloc = std::allocator<void>; <template-parameter-2-4> = void; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]' at /opt/compiler-explorer/gcc-12.3.0/include/c++/12.3.0/bits/shared_ptr_base.h:958:11,
    inlined from 'std::__shared_count<_Lp>::__shared_count(_Ptr, _Deleter) [with _Ptr = Test*; _Deleter = std::default_delete<Test []>; <template-parameter-2-3> = void; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]' at /opt/compiler-explorer/gcc-12.3.0/include/c++/12.3.0/bits/shared_ptr_base.h:939:57,
    inlined from 'std::__shared_ptr<_Tp, _Lp>::__shared_ptr(_Yp*, _Deleter) [with _Yp = Test; _Deleter = std::default_delete<Test []>; <template-parameter-2-3> = void; _Tp = Test [3]; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]' at /opt/compiler-explorer/gcc-12.3.0/include/c++/12.3.0/bits/shared_ptr_base.h:1478:17,
    inlined from 'std::shared_ptr<_Tp>::shared_ptr(_Yp*, _Deleter) [with _Yp = Test; _Deleter = std::default_delete<Test []>; <template-parameter-2-3> = void; _Tp = Test [3]]' at /opt/compiler-explorer/gcc-12.3.0/include/c++/12.3.0/bits/shared_ptr.h:232:48,
    inlined from 'void MHeap::manage() [with T = Test [3]]' at <source>:17:28,
    inlined from 'int main()' at <source>:24:25:
/opt/compiler-explorer/gcc-12.3.0/include/c++/12.3.0/bits/unique_ptr.h:132:11: note: call to 'void operator delete [](void*, std::size_t)' here
  132 |           delete [] __ptr;
      |           ^~~~~~~~~~~~~~~

此警告有效吗?

编译器:GCC 12

有趣的是,使用大小小于 3 的数组即

mem.manage<Test[2]>()
会清除警告。

c++ gcc-warning gcc12
1个回答
0
投票

new T
创建一个指向
new
的单个实例的
T
d 指针(在本例中为
T=Test[3]
)。因此,您必须使用
delete
而不是
delete[]
来释放该实例。但是,由于您正在构造一个在
shared_ptr<Test[]>
'd 指针而不是
delete[]
'd 指针上调用
new
new[]
,因此您正在调用 未定义的行为

为数组构造shared_ptr

正确
方法是使用:

std::shared_ptr<T[]> ptr(new T[size]);
// or:
auto ptr = std::make_shared<T[]>(size);

对于你的例子来说,那就是:

using Td = std::remove_extent_t<T>;

std::shared_ptr<Td[]> ptr(new Td[std::extent_v<T>]);
// or:
auto ptr = std::make_shared<Td[]>(std::extent_v<T>);

这将正确地

new[]
数组和
delete[]
它。

© www.soinside.com 2019 - 2024. All rights reserved.