【问题标题】:C++ - std::string::~string() string can still be printed as a null valueC++ - std::string::~string() 字符串仍然可以打印为空值
【发布时间】:2014-03-05 18:30:51
【问题描述】:

当我尝试std::string 时,我决定执行以下操作:

int main(int argc, char **argv)
{
    std::string s = "Hello World";
    s.~basic_string();
    std::cout << s.c_str();
}

但是,它打印nothing,并且没有垃圾。但是,在 my basic_string 类中,当调用析构函数时,我得到了垃圾。 std::string 是如何处理这个问题的?我的使用allocatorconstructs、destroys、allocates 和deallocates,但它仍然不起作用。

注意:我不是在寻找我的类的解决方案,而是要了解std::string 是如何做到的。

【问题讨论】:

  • 你知道这是非法的,对吧?
  • 未定义的行为!你刚刚度过了幸运的一天
  • 你为什么要关心你的对象被销毁后的状态?没有什么可修复的。
  • 可能是因为Short string optimization。打开 标题并自己检查:)
  • 如果我没记错的话,你应该得到一个双重释放错误,因为析构函数被调用了两次。

标签: c++ string


【解决方案1】:

首先,您不应该显式调用析构函数,除非在极少数特定情况下,这不是其中之一。当字符串超出范围时,将按照标准的保证自动调用析构函数。

其次,在使用被破坏的对象时,除了垃圾之外,您还期待什么?这是应避免的未定义行为。如果您想限制范围,请使用花括号,然后创建一个子范围并导致对象析构函数被调用并被清理。

int main(int argc, char **argv)
{
    { // new scope
      std::string s = "Hello World";
      std::cout << s;
    } // s destructor called for you

  // other stuff
}

【讨论】:

    【解决方案2】:

    在生命周期已结束的对象上调用析构函数是未定义的行为。 std::string 有一个重要的析构函数,所以当它超出范围时,它的生命周期已经结束。自动调用的析构函数会导致双重释放错误。因为它是未定义的行为,所以没有任何保证。

    Does explicitly calling destructor result in Undefined Behavior here? 详细介绍了这一点。

    【讨论】:

      【解决方案3】:

      虽然这是未定义的行为,因为对象已被破坏,但我可以猜到幕后发生的事情。

      std::basic_string 类型的对象为空时,以下构造 s[0] 仍然有效。例如

      std::string s;
      
      std::cout << s[0];
      

      在这种情况下,该类返回对 char 类型的对象的引用,该对象已被零初始化。因此,该类似乎包含这样一个具有值 char(0) 的数据成员。因此,当未分配内存时,即对象为空时,类会在调用 c_str() 时返回指向该数据成员的指针。

      所以似乎释放早期分配的内存后的析构函数将相应的指针设置为NULL。当您调用函数c_str() 时,它会检查指针是否等于NULL。如果是这样,那么它会返回指向我所描述的数据成员的指针。

      这可能是您正在寻找的解决方案。:)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-26
        • 1970-01-01
        • 1970-01-01
        • 2016-06-09
        相关资源
        最近更新 更多