C++ shared_ptr<Base>指针访问冲突
C++ shared_ptr<Base> pointer acces violation
我使用shared_ptr<Base>
与派生类的某种树列表。但是当我的树被销毁时,我得到了一个指针访问冲突
我的代码看起来像这样,除此之外,这实际上类似于我的运行时错误:
#include <iostream>
#include <memory>
#include <vector>
class Base;
typedef std::shared_ptr<Base> pBase;
class Derived;
class Base {
public:
std::vector<pBase> children;
pBase parent;
Base() {}
virtual ~Base() {}
virtual void doSomething() {}
void add(pBase i);
};
class Derived : public Base {
void doSomething() {
// Do something...
}
};
void Base::add(pBase i) {
i->parent = pBase(this);
children.push_back(i);
}
int main() {
pBase tree = pBase(new Derived());
pBase child(new Derived());
child->add(pBase(new Derived()));
tree->add(child);
}
也当我添加以下行Base::~Base
:std:: cout & lt; & lt;"销毁"<<名字& lt; & lt;std:: endl;
并在Base
中实现一个std::string,它在每个实例中都是不同的,我可以看到析构函数被多次调用(因为我认为Base::parent
引用)。这当然触发了我的错误,但我仍然不明白为什么会发生这种情况,因为shared_ptr<Base>
在实际销毁它之前应该计算它的引用!!?
我希望有人能告诉我我做错了什么!但更重要的是,我该如何补救!
看add()
中的这一行i->parent = pBase(this);
每次调用add时,都创建了一个指向this
的新共享指针。这些共享指针是分开的——也就是说,它们不是像你想象的那样是"共享的"。所以,第一次删除子节点时,它的父节点也被删除了(因为它是一个共享指针)。因此,您的代码会爆炸。
尝试(作为开始)将parent设置为一个普通的哑指针。
Base *parent;
只是为了给其他人的答案添加一些:在行中做你想做的事情的规范方式
i->parent = pBase(this);
是使用std::enable_shared_from_this
。你
从中导出
Base
class Base : std::enable_shared_from_this<Base> {
确保每个
这样的表达式中创建对象Base
实例都由一个std::shared_ptr
拥有。这在您的例子中没有问题,因为您在pBase child(new Derived());
使用
shared_from_this()
代替this
当你想要一个std::shared_ptr
。有问题的行变成i->parent = shared_from_this();
这里
i->parent = pBase(this);
你创建了一个智能指针从一个普通的旧指针到一个对象,你没有直接从new。千万不要这样做。
正如@Roddy所解释的那样,您将获得单独的智能指针对象,具有单独的引用计数器。一个指针的两个引用计数器不能工作。
在你的情况下,它可能是可以使父一个正常的指针,如@Roddy建议。这样,你就不会遇到循环引用的麻烦。只要确保在删除父指针后永远不会访问父指针即可。如果您将所有子指针与父指针一起删除(这是自动发生的,除非您在其他地方存储更多指向它们的智能指针),则没有问题
如果你想初始化一个智能指针,你有两个选择:在每个接口中使用智能指针。不幸的是,这对"this"不起作用,因为这是一个隐式参数。您需要将已经创建的智能指针以额外参数的形式手动传递给该方法。这样的:
tree->add(tree, child);
这有点难看,所以你可能想要考虑让"add"成为一个静态方法,这样你就不需要传递父类两次了。
另一种选择:使用另一种智能指针,如boost::intrusive_ptr,您可以将引用计数存储在指针中。这样,即使您只有一个像" This "这样的哑指针,也可以找到引用计数。
编辑:下面@jpalecek的答案更好。用那个。塞巴斯蒂安。- 1d 智能指针不适用于语法 (*)++
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 为什么使用 "this" 指针调用派生成员函数?
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用指针从C++中的数组中获取最大值
- 助记符和指向成员语法的指针
- <Base> <Derived> 具有相同原始指针共享引用的 shared_ptr 和 shared_ptr 实例是否计数?
- 指向派生类的指针中的"static_cast<Base*>(static_cast<void*>(派生))"何时有效?
- 智能指针:是否创建了对象的'base'部分?
- "base operand of ‘->’ has non-pointer type" 但它是指针
- C 删除base或Dynamic_cast指针
- C++返回static_cast指针导致的双重释放<Base>
- 由于标准而指向 Base 数据成员的指针类型
- 使用 static_cast、dynamic_cast 或显式转换进行派生指向 Base 指针转换的指针不会调用 base 函数
- CComPtrBase::~解除分配智能指针时,CComPtr Base崩溃
- C++ 如何将 std::vector<Derived*> 类型的指针设置为 std::vector<Base* 类型的对象>
- 如果 Derived 没有向 Base 添加新成员(并且是 POD),则可以安全地完成哪种指针强制转换和取消引用
- 为什么我不能将指向派生类成员函数的指针强制转换为相同但类 Base 的函数?
- 通过指向派生类(而不是Base类)的指针删除
- C++ shared_ptr<Base>指针访问冲突