【问题标题】:Will std::basic_string destroy null termination every time?std::basic_string 每次都会破坏空终止吗?
【发布时间】:2020-07-19 00:37:11
【问题描述】:

最近,我将我的编译器从 gcc-4.3.x 更新到 gcc-7.x,然后我的一位测试人员遇到了 Assert 异常。

代码如下:

struct data {
    data() : _c(0) { ++CREATED; std::cout<<"data  CREATED +1"<<_c<<" addres: "<<&_c<<std::endl;}
    data(char c) : _c(c) { ++CREATED; std::cout<<"data  with C CREATED +1"<<_c<<std::endl;}
    data(const data& rhs) : _c(rhs._c) { ++COPIED; }
    ~data() { ++DESTROYED; std::cout<<"data  DESTROYED +1"<<_c<<std::endl;}

    char _c;

    static size_t CREATED;
    static size_t COPIED;
    static size_t DESTROYED;
};

size_t data::CREATED   = 0;
size_t data::COPIED    = 0;
size_t data::DESTROYED = 0;

void testStringReferenceCopiable() {
    typedef std::basic_string<data> data_str;
    std::cout<<"1"<<std::endl;
    data d[] = {'a', 'b', 'c'};
    std::cout<<"2"<<std::endl;
    data_str s( &d[0], 3 );
    std::cout<<"3"<<std::endl;
    data_str s2 = s;
    std::cout<<"4"<<std::endl;
    data_str s3;
    std::cout<<"5"<<std::endl;
    s3 = s;
}

对于 gcc7.x 的输出如下:

1
data(char c) CREATED +1a
data(char c) CREATED +1b
data(char c) CREATED +1c
2
data()  CREATED +1
~data()  DESTROYED +1
3
data()  CREATED +1
~data()  DESTROYED +1
4
data()  CREATED +1
~data()  DESTROYED +1
5
data()  CREATED +1
~data()  DESTROYED +1
~data()  DESTROYED +1c
~data()  DESTROYED +1b
~data()  DESTROYED +1a

对于gcc4.3.x版本,输出为:

data  CREATED +1
1
data  with C CREATED +1a
data  with C CREATED +1b
data  with C CREATED +1c
2
3
4
5
data  DESTROYED +1c
data  DESTROYED +1b
data  DESTROYED +1a

data  DESTROYED +1


基本上我可以理解为什么它每次都调用 Construct of data() ,可能是因为空终止符。但我不明白为什么它每次都调用数据的析构函数。谁能给我答案?

谢谢!

【问题讨论】:

  • 您正在对 std::basic_string 的内部工作进行单元测试?这是一个明智的测试吗?
  • 如果你不想让代码在对象死亡时运行,不要让它的析构函数变得不重要
  • 从 gcc 9.这个代码甚至不会编译。 static_assert(is_trivial_v&lt;_CharT&gt; &amp;&amp; is_standard_layout_v&lt;_CharT&gt;); 失败。
  • 这里很多地方的未定义行为。新版本的 gcc 将其标记为红旗只是时间问题。
  • 添加空终止的实现,例如buffer[length] = CharT{} 可以解释这种行为,因为它创建了一个临时对象来复制。您应该查看标准库中basic_string 的实际实现以获得具体答案。

标签: c++ c++11 gcc7


【解决方案1】:

GCC 5 更改了 std::basic_string 以符合 C++11 中引入的几个新要求。

您注意到的变化是 GCC 5 中 std::basic_string 放弃了“写入时复制”。也就是说,相同字符串的副本必须是不同的,而不仅仅是引用计数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 2011-07-05
    • 1970-01-01
    相关资源
    最近更新 更多