[英]is this code safe? cast a std::vector<Derived*> to std::vector<Base*>
Basically I've a class A
and a class B : public A
. 基本上我有一个
class A
和一个class B : public A
And I'd like to cast a std::shared_ptr<std::vector<A*>
to a std::shared_ptr<std::vector<B*>
我想将
std::shared_ptr<std::vector<A*>
转换为std::shared_ptr<std::vector<B*>
The problem is std::vector<B>
doesn't inherit from std::vector<A>
, and the smart_ptr
neither. 问题是
std::vector<B>
不从std::vector<A>
继承,而smart_ptr
也没有。 So I do a horrible cast : 所以我做了一个可怕的演员 :
std::shared_ptr<VectorA> vector_a = * ((std::shared_ptr<VectorA>*)&vector_b);
The code compiles and runs there, but it is safe? 代码编译并在那里运行,但它是安全的吗? http://liveworkspace.org/code/3dQTz1$0
http://liveworkspace.org/code/3dQTz1$0
This is a horrible solution. 这是一个可怕的解决方案。 When you cast a vector of objects of one type to the other you can expect all kind of incorrect/undefined behaviour.
当您将一种类型的对象向量转换为另一种类型时,您可能会遇到所有类型的错误/未定义行为。
You should use vector of std::shared_ptr<A>
from the beginning and initialize them with pointers to objects of type B
there. 您应该从头开始使用
std::shared_ptr<A>
向量,并使用指向B
类型对象的指针对它们进行初始化。
If it is not possible you can create a new vector holding std::weak_ptr<A>
to avoid managing these objects twice. 如果不可能,您可以创建一个包含
std::weak_ptr<A>
的新向量,以避免两次管理这些对象。
Don't do that. 不要那样做。
Consider that a vector of (pointers to) B
is not a vector of (pointers to) A
, or to be more precise, is not a universally valid substitution for a vector of (pointers to) A
; 考虑到(指向)
B
的向量不是(指向) A
的向量,或者更确切地说,不是对(指针) A
的向量的通用有效替换; thus, there is a good reason why you cannot perform such a conversion. 因此,有充分的理由说明你无法进行这样的转换。
Although it is true that all you have in a vector of B
is indeed a set of objects which are (also( instances of A
, consider the following algorithm: 虽然你在
B
的向量中所拥有的确实是一组对象(也是( A
实例,考虑以下算法:
void f(vector<A>& v)
{
A a;
v.push_back(a);
}
Now imagine you invoke f()
with a vector of B
. 现在假设你用向量
B
调用f()
。 That would be an attempt to add an instance of a class that is not B
to a collection which is supposed to contain only elements of type B
. 这将尝试将不是
B
的类的实例添加到应该仅包含类型B
元素的集合中。
The solution here is to make the code which accepts only a vector<A>
flexible enough to work also on a vector<B>
. 这里的解决方案是使代码只接受一个足够灵活的
vector<A>
,以便在vector<B>
。 In other words, you need to make it a template. 换句话说,您需要将其设为模板。 For instance, your template could accept as arguments only vectors of a type which is derived from
A
. 例如,您的模板只能接受从
A
派生的类型的向量作为参数。 This is quite easy to enforce with some SFINAE techniques and type traits such as std::is_base_of
. 使用一些SFINAE技术和类型特征(如
std::is_base_of
可以很容易地实现这一点。
Strictly speaking the dereferencing operations should succeed. 严格来说,解除引用操作应该会成功。 Both vectors are pointer containers, so casting one to another, whilst unacceptable for production code, will still use the same dimensions and alignment.
两个向量都是指针容器,因此将一个转换为另一个,虽然生产代码不可接受,但仍将使用相同的尺寸和对齐方式。
C++ provides rich abstractions to avoid these shenanigans though, it would be better to populate the vector of derived objects as pointers to the base class. C ++提供了丰富的抽象来避免这些恶作剧,但最好将派生对象的向量填充为基类的指针。
You can still cast the elements: 你仍然可以投射元素:
A* a = vector_b->at (42);
gives you what you want. 给你你想要的。
Now, if you have written functions taking shared_ptr<vector<A*>>
as arguments, then you have multiple solutions to take you out of this situation: 现在,如果你已经编写了将
shared_ptr<vector<A*>>
作为参数编写的函数,那么你有多个解决方案可以让你摆脱这种情况:
shared_ptr<A*[]>
instead of shared_ptr<vector<A*>>
(it works as you'd like to) shared_ptr<A*[]>
shared_ptr<vector<A*>>
而不是shared_ptr<vector<A*>>
(它可以按您的意愿工作) A**
as arguments (and use vector_b->data ()
) : it does not ties you to shared pointers. A**
作为参数(并使用vector_b->data ()
):它不会将您vector_b->data ()
到共享指针。 A
(recall that operator->
chains) A
(回想operator->
链) std::vector<std::shared_ptr<A>>
(wastes resources) std::vector<std::shared_ptr<A>>
(浪费资源)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.