存储在异常对象中的信息:在异常中提供字符串

时间:2013-05-28 08:49:03

标签: c++ string exception memory-management

我想做点什么

FileIn::FileIn(const char* filename)
    {
    handle=CreateFile(filename,GENERIC_READ,FILE_SHARE_READ
        ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

    if(handle==INVALID_HANDLE_VALUE)
        {
     // Base class ExceptionWinapi will call GetLastError();
        throw ExceptionWinapiFile(filename);
        }
    }

但是,如果ExceptionWinapi不复制文件名,则在捕获异常时可能无效。但复制文件名需要malloc(如果缓冲区不是固定长度),可能会失败。那么在哪里存储字符串?

编辑:为了更清楚,请考虑

#include <cstdio>

class Foo
    {
    public:
        Foo(const Foo& foo){printf("Foo copy\n");}
        Foo(){printf("Foo\n");}
        ~Foo(){printf("~Foo\n");}
    };

class TestExcep
    {
public:
        TestExcep(const Foo& bar):m_bar(bar){}
    private:
        Foo m_bar;
};

class Test
    {
    public:
        Test(const Foo& bar)
            {throw TestExcep(bar);}
};

int main()
    {
    try
        {
        Foo bar;
        Test a(bar);
        }
    catch(const TestExcep& excep)
        {
        printf("Error\n");
        return 1;
        }
    return 0;
    }

打印(添加评论)

Foo
Foo copy
~Foo               <======Destroy old Foo after copy to the exception object!
Error
~Foo

编辑2:如果Foo(const Foo&amp; foo){printf(“Foo copy \ n”);}抛出,那么它就是那个不是旧的异常。这也很糟糕。

编辑3:

ExceptionWinapiFile的有用部分

ExceptionWinapiFile(const char* filename)
    {
    m_length=streln(filename)+1;
    m_buffer=(char*)malloc(m_length*sizeof(char));
    if(m_buffer==NULL)
        {
        //The problem
        abort(); //????
        }
    memcpy(m_buffer,filename,m_length*sizeof(char));
    }

另外(同样的问题)

ExceptionWinapiFile(const ExceptionWinapiFile& e)
    {
    m_length=e.m_length;
    m_buffer=(char*)malloc(m_length*sizeof(char));
    if(m_buffer==NULL)
        {
        //The problem
        abort(); //????
        }
    memcpy(m_buffer,e.filename,m_length*sizeof(char));
    }

dtor没问题,至少:

~ExceptionWinapiFile()
     {
     free(m_buffer);
     m_buffer=NULL; //As recommended by boost
     }

1 个答案:

答案 0 :(得分:1)

你只需要面对这样一个事实:创建一个包含任意大小字符串的异常必须分配内存,这可能会失败。你唯一能做的就是缓解。

首先,可能发生的最糟糕的事情是throw子表达式成功,但是将异常复制到异常存储器会抛出。在这种情况下,std :: terminate立即被调用,你被搞砸了。你不希望这样。

在实践中,这很少是一个问题,因为这个副本通常会被删除,这意味着没有机会抛出。此外,如果您使用的是C ++ 11,请确保您的异常具有无抛出移动构造函数。它将优先于复制构造函数使用,因此您不会冒异常的风险。

其次,throw子表达式本身可能会抛出。如果是这样,那么将抛出新的异常而不是您想要的异常。在您的情况下,如果您在异常类中有一个std :: string成员,那么您很可能会得到一个std :: bad_alloc异常而不是您想要抛出的ExceptionWinapiFile。你要问自己的问题是,这真的是一个问题吗?如果你的内存太低而无法为文件名分配足够的空间,你真的还在乎文件没有被打开吗?有可能因为内存不足而失败,如果它没有失败,无论你怎么处理文件都可能因内存不足而失败。

除非你有非常非常具体的要求,否则我说不要担心。把std :: string成员放在那里,你会没事的。