Date: Fri, 26 Feb 2016 21:55:49 +0000
| I don't think that is the right interface for such functionality. No matter what you
| do with the pointer, if you create a situation where an int* and a float* can
| simultaneously exist and both can be used to load or store the same memory,
| you destroy TBAA.
+1.
See my comment about blowing off the entire planet.
Patrick, a few months ago, made a comment about how scary std::launder is -- he is right :-)
| Gaby had a paper that would guarantee that memcpy can be used to reinterpret
| the bytes of an object of one type as a value of another type; that would seem
| to fit the bill here. And you can use that to build higher-level operations, such as
| this:
I was meaning to update that paper for Jacksonville, because it has to go in C++17, but life happened.
This that paper is the consensus of SG12 (as we reviewed it in Kona), I will make sure it gets honorable mention in Jacksonville and we have a full wording in the post-Jacksonville mailing for consideration for C++17 in Oulu.
|
| template<typename T, typename U> T *change_object_type(U *p) {
| static_assert(sizeof(T) == sizeof(U));
| static_assert(is_trivially_copyable_v<T> && is_trivially_copyable_v<U>);
| char buffer[sizeof(T)];
| memcpy(buffer, p, sizeof(T));
| p->~U();
| T *result = new (p) T;
| memcpy(result, buffer, sizeof(T));
| return result;
| }
|
| int foo(float f) {
| int *i = change_object_type<int>(&f); // float is dead, long live the int!
| return *i;
| }
|
| Your compiler ought to be able to be able to optimize that down to essentially
| nothing (maybe a round-trip through memory to convert a floating-point
| register to an integer register, or maybe just a mov from one register to
| another, depending on CPU architecture, ABI, etc.).
-- Gaby
| do with the pointer, if you create a situation where an int* and a float* can
| simultaneously exist and both can be used to load or store the same memory,
| you destroy TBAA.
+1.
See my comment about blowing off the entire planet.
Patrick, a few months ago, made a comment about how scary std::launder is -- he is right :-)
| Gaby had a paper that would guarantee that memcpy can be used to reinterpret
| the bytes of an object of one type as a value of another type; that would seem
| to fit the bill here. And you can use that to build higher-level operations, such as
| this:
I was meaning to update that paper for Jacksonville, because it has to go in C++17, but life happened.
This that paper is the consensus of SG12 (as we reviewed it in Kona), I will make sure it gets honorable mention in Jacksonville and we have a full wording in the post-Jacksonville mailing for consideration for C++17 in Oulu.
|
| template<typename T, typename U> T *change_object_type(U *p) {
| static_assert(sizeof(T) == sizeof(U));
| static_assert(is_trivially_copyable_v<T> && is_trivially_copyable_v<U>);
| char buffer[sizeof(T)];
| memcpy(buffer, p, sizeof(T));
| p->~U();
| T *result = new (p) T;
| memcpy(result, buffer, sizeof(T));
| return result;
| }
|
| int foo(float f) {
| int *i = change_object_type<int>(&f); // float is dead, long live the int!
| return *i;
| }
|
| Your compiler ought to be able to be able to optimize that down to essentially
| nothing (maybe a round-trip through memory to convert a floating-point
| register to an integer register, or maybe just a mov from one register to
| another, depending on CPU architecture, ABI, etc.).
-- Gaby
Received on 2016-02-26 22:56:00