[英]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
的值恢复为旧值?
有两种解决方案。 第一个(最好)是使用复制和交换:
myString& operator= ( myString other ) {
swap (*this, other);
return *this;
}
如果在复制构造函数中分配失败,我们将永远不会进行交换,因此不必担心会覆盖当前状态。 有关更多信息,请参阅什么是复制和交换?
另一种方法是只是确保仅在安全的情况下delete
其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=
)是使用完整的copy-swap实现。
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);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.