std::make_shared 值是否初始化默认构造函数未初始化的 class 成员?
Does std::make_shared value initialize class members whose default ctor does not initialize?
当存在无法初始化其成员的默认 ctor 时,是否 std::make_shared 值初始化成员?
我在使用 class 时偶然发现了这一点,其中默认 ctor 未使用 RAII 样式初始化成员并发出警告,并且想知道为什么在其他地方使用它时没有发出警告。在其他地方它正在使用 std::make_shared 我在想为什么它之前一直在工作并且没有发出警告。
#include <iostream>
#include <memory>
class Foo
{
public:
Foo() {} // should initalize mode but does not
int mode;
bool isZero() const
{
if (mode == 0) {
return true;
}
return false;
}
};
int main(int argc, const char* argv[])
{
auto blaa = std::make_shared<Foo>();
if (blaa->isZero()) { // No warning. Always zero initialized because using make_shared?
std::cout << "blaa.mode is zero\n";
}
Foo foo;
if (foo.isZero()) { // warning: 'foo' is used uninitialized in this function - as expected
std::cout << "foo.mode is zero\n";
}
return 0;
}
不,make_shared
在构造对象方面与以任何其他方式构造对象时发生的情况没有任何不同。所有对象在用 C++ 构造时都遵循相同的规则。
您的构造函数无法初始化 mode
。仅仅因为它恰好为零,当它在动态范围内构造时,使用您的编译器和操作系统:这并不意味着什么,并且这并不能保证您在自动构造对象时会发生什么范围(反之亦然)。
这是未定义的行为。就编译器警告而言:编译器没有义务针对未定义的行为发出警告消息。任何此类警告信息都应被简单地视为意想不到的奖励和惊喜。您的编译器没有在您的两个测试用例之一中检测到未定义的行为,事实就是如此。
使用 make_shared 您正在创建一个共享指针,它通过指针保留对象的所有权。这意味着有一个内部计数器可以跟踪此所有权。这里有更详细的解释:https://en.cppreference.com/w/cpp/memory/shared_ptr。正如 Sam Varshavchik 在他的回答中提到的那样 make_shared 在初始化方面不会做任何不同的事情。
您可能想知道为什么当您使用 make shared 时 mode 与简单的 Foo 声明有不同的值,就像你在这张照片中看到的那样:
Locals view in Visual Studio
0xcdcdcdcd 位模式表示此内存已由内存分配器(malloc() 或 new)初始化,但尚未由您的软件(对象构造函数或本地代码)。
0xcccccccc 位模式用于初始化堆栈数据中的内存。
当存在无法初始化其成员的默认 ctor 时,是否 std::make_shared 值初始化成员?
我在使用 class 时偶然发现了这一点,其中默认 ctor 未使用 RAII 样式初始化成员并发出警告,并且想知道为什么在其他地方使用它时没有发出警告。在其他地方它正在使用 std::make_shared 我在想为什么它之前一直在工作并且没有发出警告。
#include <iostream>
#include <memory>
class Foo
{
public:
Foo() {} // should initalize mode but does not
int mode;
bool isZero() const
{
if (mode == 0) {
return true;
}
return false;
}
};
int main(int argc, const char* argv[])
{
auto blaa = std::make_shared<Foo>();
if (blaa->isZero()) { // No warning. Always zero initialized because using make_shared?
std::cout << "blaa.mode is zero\n";
}
Foo foo;
if (foo.isZero()) { // warning: 'foo' is used uninitialized in this function - as expected
std::cout << "foo.mode is zero\n";
}
return 0;
}
不,make_shared
在构造对象方面与以任何其他方式构造对象时发生的情况没有任何不同。所有对象在用 C++ 构造时都遵循相同的规则。
您的构造函数无法初始化 mode
。仅仅因为它恰好为零,当它在动态范围内构造时,使用您的编译器和操作系统:这并不意味着什么,并且这并不能保证您在自动构造对象时会发生什么范围(反之亦然)。
这是未定义的行为。就编译器警告而言:编译器没有义务针对未定义的行为发出警告消息。任何此类警告信息都应被简单地视为意想不到的奖励和惊喜。您的编译器没有在您的两个测试用例之一中检测到未定义的行为,事实就是如此。
使用 make_shared 您正在创建一个共享指针,它通过指针保留对象的所有权。这意味着有一个内部计数器可以跟踪此所有权。这里有更详细的解释:https://en.cppreference.com/w/cpp/memory/shared_ptr。正如 Sam Varshavchik 在他的回答中提到的那样 make_shared 在初始化方面不会做任何不同的事情。
您可能想知道为什么当您使用 make shared 时 mode 与简单的 Foo 声明有不同的值,就像你在这张照片中看到的那样: Locals view in Visual Studio
0xcdcdcdcd 位模式表示此内存已由内存分配器(malloc() 或 new)初始化,但尚未由您的软件(对象构造函数或本地代码)。
0xcccccccc 位模式用于初始化堆栈数据中的内存。