1

I am able to typecast reference of vector<void*> to reference of vector<Foo*> whereas I am unable to typecast vector<void*> to vector<Foo*>. I am getting the error C2440: 'reinterpret_cast' : cannot convert from 'std::vector<_Ty>' to 'std::vector<_Ty>' why?

And I am able to typecast void* to Foo* without getting compiler error.

void* g =&foo;
reportFooVector2(reinterpret_cast<Foo*>(g));

Below is my entire code.

#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;

struct Foo
{
  string s;
  int i;
};


void reportFooVector( vector <Foo*> * pvf )
{

}


void reportFooVector1( vector <Foo*> pvf )
{
}

void reportFooVector2( Foo *pvf )
{
}


int main()
{
    struct Foo foo = {"foo",  5};
    struct Foo goo = {"goo", 10};
    void* g =&foo;
    reportFooVector2(reinterpret_cast<Foo*>(g));
    vector <void *> vf;
    vf.push_back(&foo);
    vf.push_back(&goo);
    reportFooVector1( reinterpret_cast< vector < Foo * >  >(vf));
    reportFooVector( reinterpret_cast< vector < Foo * > * >(&vf));
}

In the above program I am getting the compiler error C2440: 'reinterpret_cast' : cannot convert from 'std::vector<_Ty>' to 'std::vector<_Ty>' when calling the line reportFooVector1( reinterpret_cast< vector < Foo * > >(vf));

Could you please anyone tell the reason for it?

user369287
  • 692
  • 8
  • 28
  • the is an exception for `void*` that says it is allowed to be cast to and from any other pointer type. There is no such exception for `std::vector` – 463035818_is_not_an_ai Sep 25 '18 at 12:17
  • 2
    The reason is that it's not allowed in C++. An lvalue expression can only be reintepret_cast-ed to a ***reference*** to a type, unless the lvalue expression is a pointer, an integer, and enumeration, etc... Since a vector is neither, the only thing a vector can be reinterpret_casted is a reference. – Sam Varshavchik Sep 25 '18 at 12:17
  • 4
    Those are pointers, not references. Not a nitpick, since C++ has actual references and those are distinct types from pointers. Best to get terms correct to avoid confusion. – StoryTeller - Unslander Monica Sep 25 '18 at 12:17
  • @SamVarshavchik seems a perfect answer to me, why post it in a comment ? – darune Sep 25 '18 at 12:34
  • Why are you storing a vector of void* pointers in the first place? – Paul Belanger Sep 25 '18 at 12:36
  • @SamVarshavchik Doesn't this violate strict aliasing? `vector` and `vector` are different (unrelated?) types, right? I've even read that `void*`s and `foo*`s may be a different size: https://stackoverflow.com/questions/52449090/why-do-i-have-to-reinterpret-cast-pointer-pointers#comment91841719_52449090 – Jonathan Mee Sep 25 '18 at 12:39
  • @JonathanMee - The cast is never a strict aliasing violation. It's only using the result pointer/reference for access that violates strict aliasing. – StoryTeller - Unslander Monica Sep 25 '18 at 12:48
  • `vf.push_back(&goo);` Here you send pointer to pointer. – Angelicos Phosphoros Sep 25 '18 at 12:57
  • @StoryTeller Right of course, but presuming that the `vector` will be used in the not toy example this is invalid. – Jonathan Mee Sep 25 '18 at 13:09
  • @PaulBelanger - Hi, In my application I have subclassed CMFClistCtrl. I have common function OnLvnGetdispinfo() and common vector to load data and I am using this list control object in many files. – user369287 Sep 26 '18 at 12:15
  • If you subclass CMFClistCtrl, then why not just use a `vector`? – Paul Belanger Sep 26 '18 at 12:42

1 Answers1

0

First at a high level what does reinterpret_cast do?

  • Converts any pointer type to any other pointer type, even of unrelated classes
  • Cast pointers to or from integer types

Note that everything done here involves casting between, to, or from pointer types. So it's important to note that reinterpret_cast<vector<Foo*>>(vf) is not valid, as it casts a vector<void*> to a vector<Foo*>. All though these are vectors that contain pointers, neither vf nor vector<Foo*> is itself a pointer.

Having addressed this lets discuss reinterpret_cast<vector<Foo*>*>(&vf) this is also will result in undefined behavior if it is dereferenced because of the rules on Type Aliasing.
Given that the input to the reinterpret_cast is DynamicType and the output is AliasedType the reinterpret_cast is valid only if:

  • AliasedType and DynamicType are similar
  • AliasedType is the (possibly cv-qualified) signed or unsigned variant of DynamicType
  • AliasedType is std::byte, char, or unsigned char: this permits examination of the object representation of any object as an array of bytes

Informally, two types are similar if, ignoring top-level cv-qualification:

  • They are the same type
  • They are both pointers, and the pointed-to types are similar
  • They are both pointers to member of the same class, and the types of the pointed-to members are similar
  • They are both arrays of the same size or both arrays of unknown bound, and the array element types are similar

Since none of these are true with respect to vector<void*>* and vector<Foo*>* dereferencing the output of this reinterpret_cast is undefined behavior.


Now that we've discussed why these are both undesirable; let me suggest that you instead do: void reportFooVector(void** pvf, const size_t count) You can call this by doing: reportFooVector(data(vf), size(vf)) Internally to reportFooVector you'd need to cast individual elements to Foo*s in order to operate on them.

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288