Reputation: 10740
I've written a series of function templates to convert arbitrary stuff to text as painlessly as possible. For example,
print(std::pair<int, int> {13, 1});
will print {13, 1}
and something longer like
std::vector<std::tuple<double, std::string>> vect;
for(int i=0;i<3;++i) {
double root = sqrt(i);
vect.push_back( {root, "sqrt " + std::to_string(i) } );
}
print(vect);
Will output: { {0, "sqrt 0" }, {1, "sqrt 1"}, {1.41421, "sqrt 2"} }
Let's say I have the following struct:
struct point { int x, y; };
How dangerous is it to write something like the following code?
std::vector<point> my_points;
//Add points into my_points;
print(reinterpret_cast<const std::vector<std::pair<int, int>>&>(my_points));
It compiles in gcc and it produces the expected output, although I'm concerned it could fail if someone were to try porting the code.
Upvotes: 0
Views: 125
Reputation: 6200
Instead of passing a std::vector<T>
, you could pass two const T*
, one const T*
and a length, or a struct of two pointers.
Now you know that there is no specialization (as with the case std::vector<bool>
, see Why is vector<bool> not a STL container?) going on, and you also know that you have contiguous memory of T:s. Now provided that you know that
Foo
s and Bar
s have exactly the same layout (alignment, size)Foo
s and Bar
s share used behavior (If there is a function f(Foo)
, and that you use that function in print
, there must also be a semantically identical function f(Bar)
). A more theoretical formulation would be something like: Foo
is equivalent to Bar
with respect to f
.Then, it should be safe, but you are on your own, because the compiler cannot really check (2). As an example, take two version of Point (lets use float
instead of int
):
struct PointXY{float x;float y;};
struct PointYX{float y;float x;};
float inner_product(PointXY p1,PointXY p2)
{return p1.x*p2.x + p1.y*p2.y;}
float inner_product_with_important_y(PointXY p1,PointXY p2)
{return 0.5f*( p1.x*p2.x + 4.0f*p1.y*p2.y );}
That is, you can safely call inner_product
with any combination PointXY
and PointYX
(both (1) and (2) are fulfilled), but as soon as you call the anisotropic version, you will get wrong results ((1) is fulfilled, but not (2)).
Upvotes: 0
Reputation: 41780
Very dangerous. You have undefined behavior. std::vector<std::pair<int, int>>
and std::vector<Point>
are completely, district and separated classes that have no relation to each other. Reinterpreting one to another will be undefined behavior.
In fact, there are cases defined by the standard that will happen to not work to. Try casting a std::vector<char>
to std::vector<bool>
. Even though char
and bool
have the same size, both vector are not compatible.
If you want to avoid copying the buffer, consider using templates:
template<typename T>
void print(const std::vector<T>& vec) {
// ...
}
Even better, don't force vector. If you have a std::array<Point, n>
, you might want your function to work:
template<typename T>
void print(const T& range) {
// ...
}
Upvotes: 1
Reputation: 62583
First of all, you are not doing any dynamic casting here, since there is no a single call to dynamic_cast
in your code. What you are doing here is the reinterpet_cast
, produced by the c-cast
.
Second of all, no, it is not safe and is undefined behavior on many levels.
Upvotes: 3