简体   繁体   English

这段代码安全吗? 施放std :: vector <Derived*> 到std :: vector <Base*>

[英]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*>>作为参数编写的函数,那么你有多个解决方案可以让你摆脱这种情况:

  • use 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*>> (它可以按您的意愿工作)
  • take A** as arguments (and use vector_b->data () ) : it does not ties you to shared pointers. A**作为参数(并使用vector_b->data () ):它不会将您vector_b->data ()到共享指针。
  • Better: take iterators which dereference as [smart] pointers to A (recall that operator-> chains) 更好:采取迭代器,其解引用为[智能]指针A (回想operator->链)
  • use std::vector<std::shared_ptr<A>> (wastes resources) 使用std::vector<std::shared_ptr<A>> (浪费资源)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C ++转换std :: vector <Derived> *到std :: vector <Base> ……? - C++ casting a std::vector<Derived>* to std::vector<Base> …? 具有派生对象的基类的std :: vector - std::vector of Base class with Derived objects 将char *转换为std :: vector - Cast char* to std::vector 将std :: vector转换为另一个std :: vector - Cast std::vector as another std::vector 如何默认初始化std :: vector <Base> 基本对象和派生对象? - How to default-initialize std::vector<Base> with Base and Derived objects? 使指向基类指针std :: vector的指针指向派生类指针的std :: vector - Making a pointer to std::vector of base class pointers point to std::vector of derived class pointers C ++如何设置类型为std :: vector的指针 <Derived*> 到类型为std :: vector的对象 <Base*> - C++ How to set a pointer of type std::vector<Derived*> to object of type std::vector<Base*> 候选函数不可行:没有从std :: vector进行的已知转换 <derived> 到std :: vector <base> - candidate function not viable: no known conversion from std::vector<derived> to std::vector<base> 传递派生类型的 std::vector,其中需要基类型的 std::vector - Passing std::vector of derived type where a std::vector of base type is expected 如何在使用std :: vector时指定 <Base*> 存储派生* - How to specify while using std::vector<Base*> to store Derived*
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM