简体   繁体   English

如何处理C ++中new抛出的异常?

[英]How to handle an exception thrown by new in C++?

I have a class with assignment operator as below. 我有一个带有赋值运算符的类,如下所示。

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;   
}       

I am deleting memory for buff and allocating with length of new string. 我正在删除buff内存并分配新字符串的长度。 How can I handle any exception that happens during the allocation memory with new ? 如何使用new处理分配内存期间发生的任何异常? How can I restore the value of buff to old values incase of exception? 如果出现异常,如何将buff的值恢复为旧值?

There are two solutions to this. 有两种解决方案。 The first (best) is to use copy-and-swap: 第一个(最好)是使用复制和交换:

myString& operator= ( myString other ) {
    swap (*this, other);
    return *this;
}

If allocation fails in the copy constructor, we'd never get to the swap, so there's no worry about overwriting our current state. 如果在复制构造函数中分配失败,我们将永远不会进行交换,因此不必担心会覆盖当前状态。 For more, see What is copy-and-swap? 有关更多信息,请参阅什么是复制和交换?

The other approach is to just make sure you only delete if it's safe. 另一种方法是只是确保仅在安全的情况下deletedelete That is, do it after the new : 也就是说,在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;

Dealing with out-of-memory conditions is hard since there often is no easy failure path that can be used. 处理内存不足的情况非常困难,因为通常没有容易使用的故障路径。

In your case, you could try creating the new buffer before deleting the old buffer but this may increase the likelyhood of running out of memory (OOM). 在您的情况下,您可以尝试在删除旧缓冲区之前创建新缓冲区,但这可能会增加内存不足(OOM)的可能性。

Ideally you should probably use the old buffer if it is big enough and only create a new buffer if the old one is too small. 理想情况下,如果旧缓冲区足够大,则应该使用旧缓冲区;如果旧缓冲区太小,则仅创建一个新缓冲区。 In such a case it is probably ill advised to use the old buffer in the event of OOM since it will be too small to store the string. 在这种情况下,如果发生OOM,建议不要使用旧缓冲区,因为它太小了,无法存储字符串。

How can I handle any exception that happens during the allocation memory with new ? 如何使用new处理分配内存期间发生的任何异常?

A try{} catch(){} should be used to catch exceptions thrown during allocation and object creation. 应该使用try{} catch(){}来捕获在分配和对象创建过程中引发的异常。

How can I restore the value of buff to old values incase of exception? 如果出现异常,如何将buff的值恢复为旧值?

The key here is not really to restore the old values if an exception is thrown, but to first allocate and copy the contents, swapping pointers etc. and then delete the old object and memory. 如果发生异常,这里的关键不是真正恢复旧值,而是首先分配和复制内容,交换指针等,然后删除旧对象和内存。 In this way if an exception is thrown, the current contents are left unchanged. 这样,如果引发异常,则当前内容保持不变。

First allocate the memory to a temporary pointer, copy the data required, then swap the new pointer for the old one and delete the old data; 首先将内存分配给一个临时指针,复制所需数据,然后将新指针换为旧指针并删除旧数据; akin to the copy-swap idiom . 类似于复制交换的习惯用法 GotW (#59) also has a nice article on this here . 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;   
}

In general, out of memory conditions are significant, so just catching the exception may not always be ideal - it needs to be dealt with by the application as a whole, possibly even by the user for the entire system. 通常,内存不足情况很重要,因此仅捕获异常可能并不总是理想的-整个应用程序都需要处理它,甚至整个系统的用户也可能需要处理它。 A question to ask yourself is; 问自己一个问题是; what are you going to do with the exception, how are you going to recover from it? 您将如何处理该异常,如何从中恢复?


A more general solution (I assume you really are focused on implementing the operator= in the current form) is to use a full blown copy-swap implementation. 一个更通用的解决方案(我认为您确实专注于以当前形式实现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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM