当前位置:  开发笔记 > 编程语言 > 正文

std :: exception拥有什么?

如何解决《std::exception拥有什么?》经验,为你挑选了1个好方法。

我正在派生我自己的异常,调用它MyException,std::system_error从而重写what()以计算并返回我的消息.MyException的初始化列表不会调用带有消息的system_error构造函数覆盖.

如果我抓住一个MyException,并将其复制到std::exception调用的结果what()std::exception就是nullptr.这是有道理的.

我的问题是,如果我确实使用了在初始化时接收消息的system_exception的构造函数MyException,是否指定system_error将获取消息的副本并拥有它并释放它?

我假设这将使std::exception副本MyException能够返回有效的what().虽然我会在每次MyExceptions创建新内容时计算"什么"需要考虑性能.只有在首次调用what()时,我才能懒惰地计算它.

我有点担心'what'字符串的所有权what()返回a char*而不是a const std::string&.

代码是这样的(我还没有编译):

    class MyException : public std::system_error
    {
        std::string what_;
    public:
        MyException(int errorValue, const std::error_category& category)
            : std::system_error(errorValue, category)
        {}

        char* what() const
        {
           what_ = "MyException: " + to_string(code().value());
           return what_.c_str();
        }
    };

    int main()
    {
        std::exception ex;

        try
        {
            throw MyException(4, system_category());
        }
        catch( const MyException& e )
        {
            ex = e;
        }

        printf("what= %s", ex.what());

        return 1;
    }

ildjarn.. 7

我的问题是,如果我确实使用了在初始化时接收消息的system_exception的构造函数MyException,是否指定system_error将获取消息的副本并拥有它并释放它?

是的,这是由标准保证的.

首先,std::exception不拥有what- std::runtime_error是的.std::runtime_error因此定义了构造函数([runtime.error] p2-5):

runtime_error(const string& what_arg);

效果:构造一个类的对象runtime_error.
后置条件: strcmp(what(), what_arg.c_str()) == 0.

runtime_error(const char* what_arg);

效果:构造一个类的对象runtime_error.
后置条件: strcmp(what(), what_arg) == 0.

因此,它必须保存一个拷贝what_arg内部,因为没有关于传入的值的寿命要求.

接下来是[例外] p2:

T从类派生的每个标准库类exception都应具有可公开访问的复制构造函数和不能以异常退出的可公开访问的复制赋值运算符.这些成员函数应满足以下后置条件:如果两个对象lhsrhs两个具有动态型Tlhs是的副本rhs,那么strcmp(lhs.what(), rhs.what())应等于0.

因此,必须有一个复制构造函数,它必须永远不会抛出,并且副本必须保持相同的返回值what().同样,对于复制赋值运算符.

把所有这些组合起来,我们可以推测,std::runtime_error必须保留传入的值what_arg在引用计数的字符串内部(避免分配例外复制时),该值将长期存在,无论复制和/或切片-但只下到std::runtime_error,不要下来std::exception!(关于what存储的基本原理和要求的更多信息可以在@HowardHinnant的这个非常有趣的答案中找到:为std :: runtime_error移动构造函数)

std::system_error继承自std::runtime_error,所以同样适用于它以及从它派生的任何类型(只要派生类型保持非抛出复制构造函数不变).

我假设这将使std::exception副本MyException能够返回有效的what().

没有!当你犯了一个std::exception 副本MyException,你是切片对象降到更低派生类型比这里what的值的物理存储位置.如果必须复制异常,则可以使用的派生类型最少std::runtime_error.(您可以随时安全地进行std::exception 参考MyException,当然).换一种方式,它是永远不会可能获得从一个有意义的字符串std::exception 对象what().


此代码具有您想要的行为,可移植:

#include 
#include 
#include 
#include 

class MyException : public std::system_error {
public:
    MyException(int errorValue, std::error_category const& category)
      : std::system_error(
            errorValue, category,
            "MyException: " + std::to_string(errorValue)
        )
    { }
};

int main() {
    std::runtime_error ex;

    try {
        throw MyException(4, system_category());
    } catch(MyException const& e) {
        ex = e;
    }

    std::printf("what= %s", ex.what());
}

我会说,这是一种欠佳编写分配(原因很明显)异常的构造,但考虑到每一个现行标准库的实现,我所知道的用途短串优化了std::basic_string<>,这是极不可能永远是一个问题在实践中.



1> ildjarn..:

我的问题是,如果我确实使用了在初始化时接收消息的system_exception的构造函数MyException,是否指定system_error将获取消息的副本并拥有它并释放它?

是的,这是由标准保证的.

首先,std::exception不拥有what- std::runtime_error是的.std::runtime_error因此定义了构造函数([runtime.error] p2-5):

runtime_error(const string& what_arg);

效果:构造一个类的对象runtime_error.
后置条件: strcmp(what(), what_arg.c_str()) == 0.

runtime_error(const char* what_arg);

效果:构造一个类的对象runtime_error.
后置条件: strcmp(what(), what_arg) == 0.

因此,它必须保存一个拷贝what_arg内部,因为没有关于传入的值的寿命要求.

接下来是[例外] p2:

T从类派生的每个标准库类exception都应具有可公开访问的复制构造函数和不能以异常退出的可公开访问的复制赋值运算符.这些成员函数应满足以下后置条件:如果两个对象lhsrhs两个具有动态型Tlhs是的副本rhs,那么strcmp(lhs.what(), rhs.what())应等于0.

因此,必须有一个复制构造函数,它必须永远不会抛出,并且副本必须保持相同的返回值what().同样,对于复制赋值运算符.

把所有这些组合起来,我们可以推测,std::runtime_error必须保留传入的值what_arg在引用计数的字符串内部(避免分配例外复制时),该值将长期存在,无论复制和/或切片-但只下到std::runtime_error,不要下来std::exception!(关于what存储的基本原理和要求的更多信息可以在@HowardHinnant的这个非常有趣的答案中找到:为std :: runtime_error移动构造函数)

std::system_error继承自std::runtime_error,所以同样适用于它以及从它派生的任何类型(只要派生类型保持非抛出复制构造函数不变).

我假设这将使std::exception副本MyException能够返回有效的what().

没有!当你犯了一个std::exception 副本MyException,你是切片对象降到更低派生类型比这里what的值的物理存储位置.如果必须复制异常,则可以使用的派生类型最少std::runtime_error.(您可以随时安全地进行std::exception 参考MyException,当然).换一种方式,它是永远不会可能获得从一个有意义的字符串std::exception 对象what().


此代码具有您想要的行为,可移植:

#include 
#include 
#include 
#include 

class MyException : public std::system_error {
public:
    MyException(int errorValue, std::error_category const& category)
      : std::system_error(
            errorValue, category,
            "MyException: " + std::to_string(errorValue)
        )
    { }
};

int main() {
    std::runtime_error ex;

    try {
        throw MyException(4, system_category());
    } catch(MyException const& e) {
        ex = e;
    }

    std::printf("what= %s", ex.what());
}

我会说,这是一种欠佳编写分配(原因很明显)异常的构造,但考虑到每一个现行标准库的实现,我所知道的用途短串优化了std::basic_string<>,这是极不可能永远是一个问题在实践中.

推荐阅读
雯颜哥_135
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有