如何处理c++中new抛出的异常
How to handle an exception thrown by new in C++?
我有一个类,赋值操作符如下:
char *buff;
myString& operator= ( const myString& other )
{
cout << " myString::operator=n";
if( this != &other ){
cout<<"my string ="<<endl;
delete [] buff;
length = other.length;
buff = new char[length];
my_strncpy( buff, other.buff, length );
}
return *this;
}
我正在删除buff
的内存并分配新字符串的长度。我如何处理在new
分配内存期间发生的任何异常?在异常情况下,如何将buff
的值恢复到旧值?
有两种解决方案。第一种(最好的)是使用copy-and-swap:
myString& operator= ( myString other ) {
swap (*this, other);
return *this;
}
如果在复制构造函数中分配失败,则永远无法获得交换空间,因此无需担心覆盖当前状态。有关更多信息,请参见什么是复制与交换?
另一种方法是确保您只delete
,如果它是安全的。也就是说,在new
:
tmp_buff = new char[other.length];
// either that threw, or we're safe to proceed
length = other.length;
my_strncpy(tmp_buff, other.buff, length);
delete [] buff;
buff = tmp_buff;
处理内存不足的情况是困难的,因为通常没有简单的故障路径可以使用。
在您的情况下,您可以在删除旧缓冲区之前尝试创建新缓冲区,但这可能会增加内存耗尽(OOM)的可能性。
理想情况下,你应该使用旧的缓冲区,如果它足够大,只有创建一个新的缓冲区,如果旧的太小。在这种情况下,可能不建议在OOM事件中使用旧的缓冲区,因为它太小而无法存储字符串。
如何处理
new
分配内存期间发生的任何异常?
try{} catch(){}
应该用来捕获在分配和对象创建过程中抛出的异常。
这里的关键不是在抛出异常时恢复旧值,而是首先分配和复制内容,交换指针等,然后删除旧对象和内存。这样,如果抛出异常,当前内容保持不变。在异常情况下,如何将
buff
的值恢复到旧值?
首先将内存分配给临时指针,复制所需的数据,然后将新指针交换为旧指针并删除旧数据;类似于拷贝交换习语。GotW(#59)在这里也有一篇很好的文章。
myString& operator= ( const myString& other )
{
if( this != &other ){
try {
char* temp_buff = other.length ? new char[other.length] : nullptr;
// I assume my_strncpy handle NULL pointers etc.
// If not, call it behind an if check for length and pointer validity
my_strncpy( temp_buff, other.buff, length );
std::swap(temp_buff, buff);
delete [] temp_buff;
length = other.length;
}
catch (std::bad_alloc& e) {
// deal with the bad_alloc...
}
catch (std::exception& e) {
// deal with the exception
}
}
return *this;
}
一般来说,内存不足的情况很重要,所以仅仅捕获异常可能并不总是理想的——它需要由应用程序作为一个整体来处理,甚至可能由整个系统的用户来处理。你要问自己的一个问题是;你将如何处理这个异常,你将如何从中恢复?
一个更通用的解决方案(我假设您真的专注于以当前形式实现operator=
)是使用一个完整的复制交换实现。
class myString {
char* buff;
std::size_t length;
// ...
};
myString::myString(myString const& src) :
buff(src.length ? new char[src.length] : nullptr),
length(src.length)
{
if (length)
std::copy(src.buff, src.buff + length, buff);
}
myString::~myString()
{
delete [] buff;
length = 0;
}
void myString::swap(myString& rhs)
{
std::swap(rhs.buff, this->buff);
std::swap(rhs.length, this->length);
}
myString& myString::operator=(myString const& rhs)
{
if (this != &rhs) {
myString temp(rhs);
swap(temp);
}
return *this;
}
// the rest of the class implementation
//... non-member swap for addition utility
inline void swap(myString& lhs, myString& rhs)
{
lhs.swap(rhs);
}
相关文章:
- 处理多个异常集合的C++方法
- 我在c++代码中生成了一个运行时#3异常
- 孤立代码块在结构中引发异常
- C++中的赋值发生,尽管右侧出现异常
- 从构造函数抛出异常时如何克服内存泄漏
- 异常属于C++中的线程还是进程
- 当类定义不可见时捕获异常
- 创建具有 new in 函数和"this is nullptr"异常的对象
- new(std::nothrow) int[n] 抛出异常
- 'new'语句是否可以在不引发异常的情况下失败?
- 具有空异常规范的运算符new在分配返回0时调用构造函数
- 运算符 new 在大量物理内存可用时引发异常
- 操作符new在异常后销毁初始化的对象
- 带有new操作符的异常和不带有new操作符的异常
- 带nothrow选项的Operator new仍然会抛出异常
- New和delete char*会导致异常
- 终止bad_alloc异常,但堆栈跟踪中没有"new"
- 如何处理c++中new抛出的异常
- C++:抛出异常,是否使用"new"?
- 如果我自己的构造函数必须在不诉诸"new"的情况下抛出,如何缓解聚合对象构造函数的异常?