0

我有以下代码:

string join(initializer_list<string_view> strings);

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

然后我有以下调用join

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

经过小型调查,我发现生成的初始化列表的第一个元素不是"this"but "\0his"。这是因为创建的临时对象的析构函数是string("this")在创建临时对象后立即调用的string_view(因此它包含无效指针)。为什么它的生命周期string("this")没有延长到完整表达式的末尾EXPECT_EQ("this", join({ string("this") }));

编辑

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

#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) 编译的该程序的输出:

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

它可能因编译器而异,因为上述程序可能格式错误。

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

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

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

为什么在string("this")调用函数之前调用临时字符串的析构join函数,或者换句话说,为什么不将生命周期string("this")延长到完整表达式的末尾join({ string("this") })

4

1 回答 1

0

我认为这里可能发生的是,您正在从对字符串的引用构造您的 initializer_list,因此当您的 initializer_list 完成构造时,该字符串超出范围。

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

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

于 2014-07-05T14:27:30.473 回答