0

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

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

private:
    std::string m_str;
};

很简单的问题,谢谢!

4

2 回答 2

6

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

于 2013-05-16T05:54:22.463 回答
2

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

那么为什么要对 RAII 大惊小怪呢?好吧,RAII(Resource Allocation Is Initialisation)的原点与异常安全有关。

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

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

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

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

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

构造一个自洽状态的对象并不是一件难事——它可能只需要将一些成员变量设置为零。事实上,有些人强烈建议您在大多数类中仅执行此操作,原因是将一些 POD 成员变量设置为零不会触发异常抛出 - 您不必担心捕获和重新抛出异常以及清理那个半构造的物体。

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

于 2013-05-16T06:39:51.020 回答