std::basic_string每次都会销毁空终止符吗?

3

最近,我将我的编译器从gcc-4.3.x更新到了gcc-7.x,然后在我的一个测试程序中遇到了一个断言异常。

代码如下:

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


我基本上可以理解为什么它每次调用data()的时候会被称为构造函数,可能是因为空终止符。但是我不明白为什么它每次都要调用数据的析构函数。有没有人能给我一个答案呢?

谢谢!


2
你正在对std::basic_string的内部工作进行单元测试?这是一个明智的测试吗? - john
如果您不希望在对象死亡时运行代码,请不要使其析构函数非平凡。 - Zuodian Hu
1
从gcc 9开始,这段代码甚至无法编译。static_assert(is_trivial_v<_CharT> && is_standard_layout_v<_CharT>); 失败了。 - Ted Lyngmo
1
这里有许多未定义行为。新版gcc很快就会发现它。 - Sam Varshavchik
1
一个添加空终止符的实现,例如 buffer[length] = CharT{},可以解释这种行为,因为它创建了一个临时对象进行复制。您应该查看标准库中 basic_string 的实际实现以获得具体答案。 - IlCapitano
1个回答

3

GCC 5 更改了 std::basic_string,以遵守在C++11中引入的几个新要求。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接