shared_ptr and slicing

9

我曾经与某人合作过,他说shared_ptr是不安全的,当从派生类向基类(即向上转换)进行强制类型转换时会出现切片问题。例如,如果有两个类A和B,其中B继承自A,则

shared_ptr<A> a(new B)

我指向了他这个链接:http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/shared_ptr.htm,其中写道:shared_ptr<T> 可以在 T* 隐式转换为 U* 的情况下隐式转换为 shared_ptr<U>。这意味着在这些情况下使用它是安全的,但他似乎并不这么认为。
2个回答

12

有人说错了,对象切片不适用于指针。即使指针使用被包装在shared_ptr中,也不会改变这一点——它在这里并没有做任何特殊的魔法,只是用其构造函数接收的值初始化了一个内部指针。

为了回答这个问题,简化后的代码可能如下所示:

template<class T> struct ptr {
    T* t;
    ptr(T* t) : t(t) {}
    // ...
};

你会失去 B 的静态类型信息,但是指向的对象不会有任何改变。

0

对象切片不适用于指针是正确的

指针是POD(仅供参考:shared_ptr不是)。

问题引用:

每当T*可以隐式转换为U*时,shared_ptr可以被隐式转换为shared_ptr。

这是关于从一种类型转换为另一种类型,这与向上转型不同。无论A是否派生自B或反之,shared_ptr<A>shared_ptr<B>之间都没有继承关系。这就是shared_ptr对象本身不会被切片的原因。

对象切片不可能不是一个问题

考虑一个没有虚析构函数的类层次结构A、B。

std::shared_ptr<A> a(new B);
auto a = std::make_shared<B>();

将捕获B的解分配器,并在需要时调用B的析构函数

std::shared_ptr<A> a((A*)(new B));

不会执行此操作,并且会导致指向的对象出现切片问题。

智能指针包装指针使用并不意味着没有任何变化

例如,使用unique_ptr具有不同的行为:

std::unique_ptr<A> a(new B);
std::unique_ptr<A> a((A*)(new B));

两者都会出现切片问题,同时

auto a = std::make_unique<B>();

不会。

使用普通指针也没有帮助:

A* a = new B{};
delete a;

这是一场灾难的配方。

示例代码可在此处找到。


你开始说原始指针不能进行切片,最后却举了一个使用原始指针进行切片的例子……我错过了什么吗? - Quentin
不是指针切片,而是被指向的对象经历了切片问题。希望这解决了你的疑惑;如果没有,我会尝试提供一个例子或其他东西,但我现在想不出来。我没有找到更好的表达方式,但如果你发现任何答案的任何部分有更好的措辞,请建议一下。 - Stefano Falasca

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接