如何正确使用全局运算符 new、new[]、delete 和 delete[]

伯努瓦·杜布勒伊

我有一个关于使用全局运算符 new、new[]、delete 和 delete[] 的问题(每个问题 1 个帖子,我吸取了教训...)但首先,我将描述情况。

在 Herb Sutter 的 Exceptional C++ 书中的第 12 项 - 编写异常安全代码 - 第 5 部分中,作者使用了以下代码段:

...
template <class T>
StackImpl<T>::StackImpl( size_t size )
    : v_( static_cast<T*>
            ( size == 0
            ? 0
            : operator new(sizeof(T)*size) ) ),
    vsize_(size),
    vused_(0)
{
} 

template <class T>
StackImpl<T>::~StackImpl()
{
    destroy( v_, v_+vused_ ); // this can't throw
    operator delete( v_ );
}
...

// construct() constructs a new object in
// a given location using an initial value
//
template <class T1, class T2>
void construct( T1* p, const T2& value )
{
    new (p) T1(value);
}

// destroy() destroys an object or a range
// of objects
//
template <class T>
void destroy( T* p )
{
    p->~T();
}

template <class FwdIter>
void destroy( FwdIter first, FwdIter last )
{
    while( first != last )
    {
        destroy( &*first );
        ++first;
    }
}

一开始没看懂,做了个小测试:

struct OperatorTest
{
    OperatorTest()
    {
        std::cout << "Constructor" << std::endl;
    }

    ~OperatorTest()
    {
        std::cout << "Destructor" << std::endl;
    }

    OperatorTest&  operator=(const OperatorTest& other)
    {
        std::cout << "Assignment" << std::endl;
        return *this;
    }
};

int main()
{
    // Operator new[]
    OperatorTest* test1 = static_cast<OperatorTest*>(operator new[](sizeof(OperatorTest) * 5)); // Only allocate memory
    new (&test1[0]) OperatorTest(); // Calls the constructor by doing a placement new
    test1[0].~OperatorTest(); // Calls the destructor
    operator delete[](test1); // Calls the destructor... again

    std::cout << std::endl;

    // Operator new
    OperatorTest* test2 = static_cast<OperatorTest*>(operator new(sizeof(OperatorTest) * 5)); // Only allocate memory
    new (&test2[0]) OperatorTest(); // Calls the constructor by doing a placement new
    test2[0].~OperatorTest(); // Calls the destructor
    operator delete(test2); // Calls the destructor... again

    std::cout << std::endl;

    {
        // How does the STL allocate memory?
        std::vector<OperatorTest> test3{ 3 }; // Allocate memory and calls the default constructor
    }

    std::cout << std::endl;

    // Manual new[] / delete[]
    OperatorTest* test4 = new OperatorTest[3];
    delete[] test4;

    return 0;
}

控制台中 main 函数的结果是:

  1. 构造函数
  2. 析构函数


  3. 构造函数

  4. 析构函数


  5. 构造函数

  6. 构造函数
  7. 构造函数
  8. 析构函数
  9. 析构函数
  10. 析构函数


  11. 构造函数

  12. 构造函数
  13. 构造函数
  14. 析构函数
  15. 析构函数
  16. 析构函数

我的问题是:

变量 test1 和 test2 是否正确创建和销毁?我对此感到不安全的一个原因是数组和单个 new/delete 运算符似乎都适用于数组。

我的推理是,即使 STL 似乎也不使用这些运算符。请参阅变量test3及其输出作为示例。

它是!

您对运算符 new 和 delete (及其数组版本)的使用似乎是正确的。

您的代码注释(“再次调用析构函数...”)表明存在误解。您似乎认为全局运算符 delete 不仅会释放内存,还会调用对象的析构函数。不是这种情况。全局运算符 new 和 delete 只分配/释放原始字节,就像 c 函数 malloc 和 free 一样。

从这个意义上说,两个操作符版本(单个与数组)实际上是一样的,只是它们应该匹配,即一个版本分配的内存块必须用相同的版本释放。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

重载new和Delete运算符

使用重载的 new 和 delete 运算符跟踪已用内存?

为什么std :: vector使用std :: allocator而不是new和delete运算符?

替换运算符new和delete似乎影响C库

了解C ++中new和delete运算符背后的逻辑

具有三个参数的重载运算符new和operator delete

为什么 new 和 delete 运算符签名与所有其他运算符不同

new / delete和:: new / :: delete有什么区别?

使用 new 和 delete 在宏中实现 C realloc

C语言中不赞成使用“ new”和“ delete”吗?

如果我为类编写new和delete运算符,是否必须编写所有重载?

malloc和free与new和delete

运算符delete抛出异常,位置为new

如何正确使用new和delete(以避免缓冲区溢出问题)

在 constexpr 函数中放置 new 和 delete

C ++:如果我重载了new运算符,是否也必须重载delete运算符?

重载new和delete,new []和delete []有什么用?

使用stringstream :: imbue和自定义全局运算符new进行调试断言失败

如何安全地为该情景使用new和delete

使用动态数组和delete运算符的boost :: python内存错误

取消分配由全局替换运算符new返回的指针而不调用替换运算符delete的未定义行为?(C ++ 17)

可以在DriverKit驱动程序中使用`new`和`delete`吗?

C ++编译器是否通常会“优化” malloc,并免费使用new和delete?

在C ++中使用自定义new / delete和Qt的Segfault

用内存池中的new和delete替换malloc和free

C++中delete()函数和delete运算符的区别?

使用替换的运算符new进行的clang链接时间优化导致valgrind中的free()/ delete不匹配

为什么C ++运算符new / delete / variant不应该放在头文件中?

new / delete和malloc / free有什么区别?