为什么 shared_ptr 中对象的地址与原始地址不同?

huangapple go评论106阅读模式
英文:

Why is the address of an object stored in shared_ptr different than the original address?

问题

我正在学习shared_ptr的用法。

我原以为shared_ptr会存储原始对象A。

这是演示代码https://godbolt.org/z/nqrMhcz95。我注意到a、b.a_和sa的地址是不同的。

结构体 A {

int getValue() {
    return a;
}
int a;

};

结构体 A1 {
int a;
};

结构体 B {
B(A& a) : a_(std::make_shared(a)), a1_(std::make_shared(A1())){};
A& getA() { return *a_; }

std::shared_ptr<A> a_;
std::shared_ptr<A1> a1_;

};

int main() {
A a;
B b{a};
std::shared_ptr
sa = std::make_shared(a);
cout << &a << '\n';
cout << &(*b.a_) << '\n';
cout << &(*sa) << '\n';
b.getA().a = 4;
cout << a.getValue() << '\n'; // 期望修改的值反映在原始对象a中
}


我是否误解了shared_ptr的行为?

我如何修改存储在shared_ptr中的对象的值?
英文:

I'm learning the usage of shared_ptr.

I was expecting the shared_ptr stores the original object A.

Here is the demo code https://godbolt.org/z/nqrMhcz95. I've noticed the address of a, b.a_ and sa are different.

struct A {

    int getValue() {
        return a;
    }
    int a;
};

struct A1 {
    int a;
};

struct B {
    B(A&amp; a) : a_(std::make_shared&lt;A&gt;(a)), a1_(std::make_shared&lt;A1&gt;(A1())){};
    A&amp; getA() { return *a_; }

    std::shared_ptr&lt;A&gt; a_;
    std::shared_ptr&lt;A1&gt; a1_;
};

int main() {
    A a;
    B b{a};
    std::shared_ptr&lt;A&gt; sa = std::make_shared&lt;A&gt;(a);
    cout &lt;&lt; &amp;a &lt;&lt; &#39;\n&#39;;
    cout &lt;&lt; &amp;(*b.a_) &lt;&lt; &#39;\n&#39;;
    cout &lt;&lt; &amp;(*sa) &lt;&lt; &#39;\n&#39;;
    b.getA().a = 4;
    cout &lt;&lt; a.getValue() &lt;&lt; &#39;\n&#39;; // expecting the modified value reflect in the original object a
}

Did I misunderstand the behaviour of shared_ptr?

How can I modify the value of an object stored in a shared_ptr?

答案1

得分: 3

在以下代码中:

A a;
std::shared_ptr&lt;A&gt; sa = std::make_shared&lt;A&gt;(a);

asa 引用不同的对象。make_shared 总是会创建一个新的对象,然后将 a 传递给新分配的 A 实例的拷贝构造函数。

要使两个变量都指向同一个对象,你需要将它们都声明为 shared_ptr,如下所示:

std::shared_ptr&lt;A&gt; a = std::make_shared&lt;A&gt;();
std::shared_ptr&lt;A&gt; sa = a;

对于 B,同样的规则适用,如果你希望其成员指向相同的对象,传递给构造函数的参数需要是一个 shared pointer。

请注意,如果你不希望所有这些对象共享对 A 的所有权,你可以使用引用来实现相同的效果,但你必须确保原始对象的生存期超过了所有引用。

不要尝试将现有对象的指针传递给 shared_ptr 构造函数:

A a;
std::shared_ptr&lt;A&gt; sa{&amp;a};

这起初似乎可以工作,asa 将引用相同的对象,但当销毁 sa 时,它将尝试删除 a,这是未定义的行为,因为 a 没有使用 new 进行分配。

英文:

In

A a;
std::shared_ptr&lt;A&gt; sa = std::make_shared&lt;A&gt;(a);

a and sa refer to different objects. make_shared will always create a new object, a is then passed to the copy constructor of the newly allocated instance of A.

To have two variables that both point to the same object you'll need both of them to be shared_ptrs:

std::shared_ptr&lt;A&gt; a = std::make_shared&lt;A&gt;();
std::shared_ptr&lt;A&gt; sa = a;

The same applies in B, if you want its member to point to the same object the parameters passed to the constructor needs to be a shared pointer.

Note that if you don't want all of these objects to share ownership of A you could achieve the same with references but you'd then have to make sure the original object outlives all the references.

Don't be tempted to pass a pointer to an existing object into the shared_ptr constructor:

A a;
std::shared_ptr&lt;A&gt; sa{&amp;a};

This will initially appear to work and a and sa will refer to the same object but when sa is destroyed it will attempt to delete a which is undefined behaviour as a wasn't allocated with new.

huangapple
  • 本文由 发表于 2023年3月12日 14:05:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/75711341.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定