微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

std::make_shared 值是否初始化其默认构造函数未初始化的类成员?

如何解决std::make_shared 值是否初始化其默认构造函数未初始化的类成员?

当存在无法初始化其成员的认构造函数时,std::make_shared 值是否会初始化成员?

我在使用认 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 与仅使用简单的 Foo 声明时 mode 有不同的值,如下图所示: Locals view in Visual Studio

0xcdcdcdcd 位模式表示该内存已由内存分配器(malloc() 或 new)初始化,但尚未由您的软件(对象构造函数或本地代码)初始化。>

0xcccccccc 位模式用于初始化堆栈上数据中的内存。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。