C ++ std :: string在任何平台上都是100%RAII?

时间:2013-05-16 05:49:57

标签: c++ string raii

据我所知,std :: string是一个RAII对象,所以我不需要在声明后进行初始化。构造函数会自动处理这些东西。但是在任何平台或任何编译器上都有任何异常吗?

class TestString
{
public:
    TestString()
    {
        // m_str.clear(); or
        // m_str = "";
    }
    virtual ~TestString(){}

private:
    std::string m_str;
};

非常简单的问题,谢谢!

2 个答案:

答案 0 :(得分:6)

std::string的默认构造函数构造一个空字符串,长度为零个字符。这是所有实现的所有平台上的默认构造函数提供的保证。

答案 1 :(得分:2)

在C ++中,初始化可能涉及构建后的几个方法调用,但这并不违反RAII。构造函数负责将对象置于自洽的有效状态 - 特别是可以安全地调用析构函数或任何其他方法。根据您的要求,这可能仅仅意味着将一些变量设置为零。

那么为什么关于RAII的大惊小怪呢?那么,RAII的原始点(资源分配是初始化)与异常安全有关。

当函数提前退出时,特别是由于抛出异常,调用析构函数非常重要 - 释放资源(例如堆内存和文件句柄)。 C ++强制要求在变量超出范围时自动发生析构函数调用。但是,异常抛出可以随时发生,至少原则上如此。如何确定您要发布的资源是否已分配?如果你不确定那个分配是否已经完成,你可以使用一个标志或一个空句柄或类似的东西,这样你就可以在析构函数中进行测试,但是你如何确定该标志已被初始化?

基本上,为了能够安全地调用析构函数,C ++需要知道该对象已经初始化。这是由构造函数处理的。但这只会导致另一个微妙的问题 - 如果在构造函数中发生异常抛出会发生什么。

长话短说 - 只有在构造函数成功完成后,C ++才会对析构函数调用负责。如果构造函数早期被异常抛出退出,则不会有析构函数调用 - 如果在构造函数中没有仔细处理(或证明不可能)异常,则可能发生内存和/或资源泄漏。

无论如何,名称的来源只是除非构造函数已经完成,否则不会认为资源已被获取,因此当且仅当构造函数成功完成时才会释放资源(通过调用析构函数)。

但这是一个简单的模型,名称可能会产生误导。在实践中,可以通过任何方法获取资源,并且语言没有关于哪种活动是初始化而哪些不是初始化的固定想法。重要的是,如果在一个尴尬的时刻抛出异常,并且结果调用了对象析构函数,它应该始终能够确切地确定需要清理什么 - 要释放哪些资源。

构建一个自洽状态的对象并不困难 - 它可能只需要将一些成员变量设置为零。实际上有些人强烈建议你在大多数类中做的不多于此,原因是将一些POD成员变量设置为零不能触发异常抛出 - 你不必担心捕获并重新抛出异常并清理该半构造对象。

每个具有析构函数的标准库类都将满足该自洽状态要求。只有“普通旧数据”类型(例如int)根据定义没有析构函数(好吧,至少没有有用的析构函数)不实现RAII,至少不是为了自己