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

时间:2018-11-28 21:04:43

标签: c++

关于使用全局运算符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;
}

控制台中主要功能的结果是:

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


  3. 构造函数

  4. 析构函数


  5. 构造函数

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


  11. 构造函数

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

我的问题是:

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

我的理由是,即使STL似乎也没有使用那些运算符。请参见变量test3及其输出作为示例。

1 个答案:

答案 0 :(得分:1)

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

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

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