使用已定义结构的向量到达未初始化的内存

The*_*ire 2 c++ c++11

我使用vector的length和value构造函数创建了一个名为xor_funcs的bitpacked向量的向量.这是失败的测试:

TEST(vectorInit, size3) {
    const xor_func temp{false, {0,0,0}};
    vector<xor_func> arr{3, temp};
    for(xor_func& f : arr) {
        EXPECT_EQ(3, f.size()) << f;
    }
    for(int i = 0; i < 3; i++) {
        ASSERT_EQ(3, arr[i].size()) << "for i=" << i;
        arr[i].set(i);
    }
}
Run Code Online (Sandbox Code Playgroud)

似乎size()调用正在访问未初始化的内存,对于长度为3或更长的向量,而不是大小为2的向量.Valgrind确认内存最近没有堆栈,malloc'd或free'd.

xor_func被定义为这样的:

class xor_func {
    private:
        boost::dynamic_bitset<> bitset;
        bool negated;
    public:
        xor_func(const bool neg, const std::initializer_list<int> lst); 
        // That's defined in cpp

        xor_func(const size_t size) : bitset(size), negated(false) {}

        // Disallow the trivial constructor, since I don't want
        // any 0 length xor_funcs existing by default.
        // xor_func() : bitset(), negated(false) {}

        xor_func(const bool negated, const boost::dynamic_bitset<> bitset)
            : bitset(bitset), negated(negated) {}
        // That's all the constructors.

        // Snip
}
Run Code Online (Sandbox Code Playgroud)

我没有对默认副本和移动构造函数做任何事情.

发生了什么,为什么我的测试失败了?

The*_*ire 5

正如dyb所说,vector<xor_func> arr{3, temp};被解释为 vector<xor_func> arr({xor_func{3}, temp}),因为它可以隐式地由构造函数3转换为a xor_func,然后它可以选择要调用的构造函数的初始化列表版本.

如果你看一下Is C++ 11 Uniform Initialization是旧式语法的替代品吗?,你可以看到统一初始化语法的缺点之一就是这个bug.一个更微不足道的例子是

// std::string constructor prototype for reference
// fill (6) 
string (size_t n, char c);

void main() {
    string myString{65, 'B'};
    cout << myString << endl;
}
Run Code Online (Sandbox Code Playgroud)

这将打印出"AB",而不是"BBBBBB ... BBB",因为它可以将65转换为'A',然后它就像我们写的那样myString{'A', 'B'}.要修复它,只需不要尝试为此调用使用统一初始化语法并将其替换为

string myString(65, 'B');
Run Code Online (Sandbox Code Playgroud)

我可以解决这个错误的另一种方法是将构造函数更改xor_func(const size_t size)explicit xor_func(const size_t size),这可以防止编译器隐式转换3xor_func.

哦,还有另一个很好的答案显式关键字在C++中意味着什么.