我已经设计了一个 gray_code
类,用于存储一些无符号整数,其底层位以格雷码顺序存储。以下是代码:
template<typename UnsignedInt>
struct gray_code
{
static_assert(std::is_unsigned<UnsignedInt>::value,
"gray code only supports built-in unsigned integers");
// Variable containing the gray code
UnsignedInt value;
// Default constructor
constexpr gray_code()
= default;
// Construction from UnsignedInt
constexpr explicit gray_code(UnsignedInt value):
value( (value >> 1) ^ value )
{}
// Other methods...
};
在一些通用算法中,我写了以下类似的代码:
template<typename UnsignedInt>
void foo( /* ... */ )
{
gray_code<UnsignedInt> bar{};
// Other stuff...
}
在这段代码中,我期望
bar
被零初始化,因此bar.value
也应该被零初始化。然而,在遇到意外错误后,我发现bar.value
被初始化为垃圾值(确切地说是4606858),而不是0u
。这让我感到惊讶,所以我去cppreference.com看一下上面的代码应该做什么...根据我的理解,形式为
T object {};
对应于value initialization。我发现这句话很有趣:“在所有情况下,如果使用空括号对{}并且T是集合类型,则执行集合初始化而不是值初始化。”
然而,
gray_code
有一个用户提供的构造函数。因此它不是一个聚合体,因此不执行aggregate initialization。 gray_code
没有采用std::initializer_list
的构造函数,因此也不执行list initialization。然后,gray_code
的值初始化应遵循C++14的通常规则:1)如果T是一个没有默认构造函数或带有用户提供的默认构造函数或删除的默认构造函数的类类型,则对象将被默认初始化。
2)如果T是一个没有用户提供或删除的默认构造函数的类类型(即可能是具有默认构造函数或隐式定义的类),则对象将被零初始化,然后如果它具有非平凡的默认构造函数,则进行默认初始化。
3)如果T是数组类型,则数组的每个元素都会被值初始化。
4)否则,对象将被零初始化。
如果我理解正确,
gray_code
具有显式默认(非用户提供的)默认构造函数,因此不适用1)。它具有默认的默认构造函数,因此适用2):gray_code
被zero-initialized。默认的默认构造函数似乎符合平凡默认构造函数的所有要求,因此不应发生默认初始化。让我们看一下gray_code
如何被零初始化:如果T是标量类型,则对象的初始值为将积分常数零隐式转换为T。如果T是非联合类类型,则所有基类和非静态数据成员都将被初始化为零,并且所有填充都将初始化为零位。构造函数(如果有)将被忽略。如果T是联合类型,则第一个非静态命名数据成员将被初始化为零,并且所有填充都将初始化为零位。如果T是数组类型,则每个元素都将被初始化为零。如果T是引用类型,则不执行任何操作。 gray_code是非联合类类型。因此,应该初始化其所有非静态数据成员,这意味着value将被初始化为零。value满足std :: is_unsigned,并且因此是标量类型,这意味着它应该使用“将积分常数零隐式转换为T”进行初始化。
因此,如果我正确地阅读了所有内容,则在上面的foo函数中,bar.value应始终使用0进行初始化,并且永远不应使用垃圾进行初始化,我是否正确?
注意:我编译代码的编译器是MinGW_w4 GCC 4.9.1(带有POSIX线程和dwarf异常),以便于帮助。虽然我有时会在计算机上获得垃圾,但我从未能够在在线编译器中获得除零以外的任何内容。
class foo {
foo() = default;
};
并且
class foo {
foo();
};
foo::foo() = default;
“等效”和“相等”是不同的,以下是来自C++14标准中[dcl.fct.def.default]章节的引用:
如果一个函数在第一次声明时没有被显式地默认或删除,则该函数是“用户提供的”,前提是它已经被用户声明。
换句话说,当我得到垃圾值时,我的默认默认构造函数确实是用户提供的,因为它在第一次声明时没有被显式地默认。因此,发生的不是零初始化,而是默认初始化。再次感谢@Columbo指出真正的问题。
= default
е…·жңүдёҖдәӣеҘҮжҖӘзҡ„规еҲҷгҖӮеңЁC++03дёӯжү§иЎҢеҖјеҲқе§ӢеҢ–зҡ„д»Јз Ғд»Қ然еңЁC++11дёӯжү§иЎҢеҖјеҲқе§ӢеҢ–гҖӮ - Morwenn