C ++括号初始化程序列表,临时生存期 [英] C++ brace initializer list, temporary lifetime

查看:215
本文介绍了C ++括号初始化程序列表,临时生存期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

string join(initializer_list<string_view> strings);

initializer_list是std :: initializer_list,而string_view不是std :: string视图,但是与const string&的构造函数非常相似的类和const char *.

initializer_list is std::initializer_list and string_view isn't std::string view but very similar class with constructors from const string& and const char*.

然后我得到了join的调用:

EXPECT_EQ("this", join({ string("this") }));

经过细致的调查,我发现生成的初始化程序列表的第一个元素不是"this"而是"\0his".这是因为string("this")创建的临时结构的析构函数在创建临时string_view之后立即被调用(因此它包含无效的指针).为什么将string("this")的生存期不延长到完整表达式EXPECT_EQ("this", join({ string("this") }));的末尾?

After small investigation I've found that the first element of resulting initializer list isn't "this" but "\0his". This is becouse the destructor of the temporary created by string("this") is called right after creation of temporary string_view (so it contains invalid pointers). Why is it so that the lifetime of string("this") isn't extended to the end of the full-expression EXPECT_EQ("this", join({ string("this") }));?

好的,正如您所建议的,有一个独立的示例:

Ok, as you suggested there is self-contained example:

#include <iostream>
#include <string>

using namespace std;

class string_view {
public:
    string_view(const string& str)
        : _begin(str.data())
        , _end(str.data() + str.size()) {
    std::cout << "string_view(...)" << std::endl;
    }

    const char* _begin;
    const char* _end;
};

void join(initializer_list<string_view> strings) {
    std::cout << "join(...)" << std::endl;
    for (auto i = 0u; i < 5; ++i) {
        std::cout << int(strings.begin()->_begin[i]) << " " << strings.begin()->_begin[i] << std::endl;
    }
}

int main() {
    join({ string("this") });
    return 0;
}

使用最后的Visual Studio C ++(Express)编译的该程序的输出:

The output of this program compiled with last Visual Studio C++ (Express):

string_view(...)
join(...)
0
104 h
105 i
115 s
0

由于上述程序的格式可能不正确,因此编译器之间可能会有所不同.

It may vary from compiler to compiler as above program is probably ill-formed.

我研究了调试器中调用的顺序是什么,并且有以下顺序:

I've investigated what is the order of calls in debugger, and there is the sequence:

main()
    basic_string(const char*)
    string_view(const string&)
    ~basic_string()
    initializer_list(...)
    join(...)

我希望在join函数中可以使用string("this")的内容.事实并非如此,因为`string("this")之前已被销毁.

I would like the content of the string("this") to be available inside join function. And it is not the case, becouse `string("this") is destroyed before.

为什么在调用join函数之前调用了临时字符串string("this")的析构函数,或者换句话说,为什么string("this")的生存期没有延长到完整表达式join({ string("this") })的末尾?/p>

Why is the destructor of temporary string string("this") invoked before the join function is called or in other words why isn't the lifetime of string("this") extended to the end of the full-expression join({ string("this") })?

推荐答案

我认为可能在这里发生的事情是,您正在根据对字符串的引用构造您的initializer_list,以便该字符串当您的initializer_list完成构造后,超出范围.

What I think might be happening here is that you are constructing your initializer_list from a reference to your string, so that the string goes out of scope when your initializer_list has finished constructing.

您看到您的字符串不是join()函数的参数,而是您构造的initializer_list的参数.

You see your string is not a parameter to the join() function but to the initializer_list you construct.

我的猜测是构造了initializer_list,您的字符串超出了范围,然后您的join()函数尝试通过string_view中包含的引用访问死字符串.

My guess is that the initializer_list is constructed, your string goes out of scope and then your join() function tries to access the dead string through the reference contained in the string_view.

这篇关于C ++括号初始化程序列表,临时生存期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆