关于使用全局运算符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;
}
控制台中主要功能的结果是:
析构函数
构造函数
析构函数
构造函数
析构函数
构造函数
我的问题是:
变量test1和test2是否正确创建和销毁?我对此不安全的原因之一是数组和单个new / delete运算符似乎都适用于数组。
我的理由是,即使STL似乎也没有使用那些运算符。请参见变量test3
及其输出作为示例。
答案 0 :(得分:1)
您对new和delete运算符的使用(及其数组版本)似乎是正确的。
您的代码注释(“再次调用析构函数...”)表明存在误解。您似乎假设全局运算符delete不仅会释放内存,还会调用对象的析构函数。不是这种情况。全局运算符new和delete仅分配/取消分配原始字节,就像c函数malloc和free一样。
从这个意义上说,两个操作符版本(单个vs.数组)实际上是相同的,只有它们应该匹配,即,一个版本分配的大量内存必须用同一版本释放。