【发布时间】:2017-04-25 11:26:48
【问题描述】:
我最近在我的程序中出现了一个错误,这让我有点吃惊,但也许它不应该,因为 C++(尤其是现代 C++)提供了大量的初始化类型。我有一个看起来像这样的类:
struct foo
{
foo(const std::set<int> &values) { values_ = values; }
set::set<int> values_;
};
在构造foos 时,通常最简单的方法是使用初始值设定项列表内联指定一组值(一个实例通常有 2-3 个在编译时已知的已知值),如下所示:
auto f = std::make_shared<foo>({ 1, 2, 3 });
然而,我记得当我第一次写课程foo时,上面的用法给我带来了编译时问题;我不记得确切的错误,但我发现显式调用 initializer_list 构造函数允许编译器正确推断出如何处理参数,如下所示:
auto f = std::make_shared<foo>(std::initializer_list<int>({ 1, 2, 3 }));
这“工作”了很长时间,但我的应用程序最近遇到了一些模糊的、看似随机的崩溃。调试后发现上面改成:
auto f = std::make_shared<foo>(std::initializer_list<int>{ 1, 2, 3 });
(即从复制初始化更改为大括号初始化程序)解决了这个问题。这让我想到了一个问题:
如上例所示的初始化列表的复制构造是不安全的做法吗?大括号初始值设定项中值的生命周期是否与全封闭表达式的生命周期不匹配?
这可能只是其他一些仍然存在的错误或某种编译器错误的症状(我使用的是 Apple clang v8.0)。
【问题讨论】:
-
请显示您的构造函数定义。
-
@KerrekSB:已添加。我真正要做的就是复制作为参数传入的
set。这是一个非常简化的版本;启发foo的实际课程要复杂得多。但是,对set进行的唯一操作如示例所示。 -
你遇到的bug与这里的初始化无关。通过一些动态清理程序(Valgrind、ASAN、TSAN)运行您的程序以找到真正的错误。
-
我看不出你有什么问题。如果你可以给我们一个minimal reproducible example 应该有助于找到问题。
-
感谢您的见解。最小化重现的测试用例将是一项艰巨的任务;我只是对这个特殊的构造感到好奇,因为它似乎对失败有直接影响,而且我对所有管理支撑初始化的规则还没有那么自信。正如@KerrekSB 指出的那样,我需要使用更多的分析工具来在这个问题上归零。
标签: c++ c++11 initializer-list