Is interpreting a pointer to first member as the class itself well defined?Pointer to class data member “::*”Check for the right typecastingarray of type voidHow to add a method to a superclass from a subclass in C++Casting a tr1::function to a void*Error while deleting a vector pointer to pointersCasting from member function pointer to another type and back, strict-aliasing issue?Why should I use a pointer rather than the object itself?Calling a method through an ill-typed pointer? Is it legal?Compilation Error on passing smart pointer to a template class member function

What do you call a painting painted on a wall?

Explaining intravenous drug abuse to a small child

Why would a military not separate its forces into different branches?

How long did it take Captain Marvel to travel to Earth?

Referring to person by surname, keep or omit "von"?

How would you say "You forget wearing what you're wearing"?

Does Thanos's ship land in the middle of the battlefield in "Avengers: Endgame"?

Can a good but unremarkable PhD student become an accomplished professor?

Is there a reason why Turkey took the Balkan territories of the Ottoman Empire, instead of Greece or another of the Balkan states?

Dual frame in Riemannian metrics.

Dimmer switch not connected to ground

Do Jedi mind tricks work on Ewoks?

Collision domain question

Given a safe domain, are subdirectories safe as well?

What is the thing used to help pouring liquids called?

How to use awk to extract data from a file based on the content of another file?

What does the coin flipping before dying mean?

Hostile Divisor Numbers

Convert Numbers To Emoji Math

What is more safe for browsing the web: PC or smartphone?

Game artist computer workstation set-up – is this overkill?

Huffman Code in C++

How to preserve a rare version of a book?

My large rocket is still flipping over



Is interpreting a pointer to first member as the class itself well defined?


Pointer to class data member “::*”Check for the right typecastingarray of type voidHow to add a method to a superclass from a subclass in C++Casting a tr1::function to a void*Error while deleting a vector pointer to pointersCasting from member function pointer to another type and back, strict-aliasing issue?Why should I use a pointer rather than the object itself?Calling a method through an ill-typed pointer? Is it legal?Compilation Error on passing smart pointer to a template class member function






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








13















I have some code that look like this:



template<typename T>
struct memory_block
// Very not copiable, this class cannot move
memory_block(memory_block const&) = delete;
memory_block(memory_block const&&) = delete;
memory_block(memory_block&) = delete;
memory_block(memory_block&&) = delete;
memory_block& operator=(memory_block const&) = delete;
memory_block& operator=(memory_block&&) = delete;

// The only constructor construct the `data` member with args
template<typename... Args>
explicit memory_block(Args&&... args) noexcept :
datastd::forward<Args>(args)...

T data;
;

template<typename T>
struct special_block : memory_block<T>
using memory_block<T>::memory_block;
std::vector<double> special_data;
;

// There is no other inheritance. The hierarchy ends here.


Now I have to store these types into type erased storage. I chose a vector of void* as my container. I insert pointers of the data member into the vector:



struct NonTrivial virtual ~NonTrivial() ;

// exposed to other code
std::vector<void*> vec;

// My code use dynamic memory instead of static
// Data, but it's simpler to show it that way.
static memory_block<int> data0;
static special_block<NonTrivial> data1;

void add_stuff_into_vec()
// Add pointer to `data` member to the vector.
vec.emplace_back(&(data0->data));
vec.emplace_back(&(data1->data));



Then later in the code, I access the data:



// Yay everything is fine, I cast the void* to it original type
int* data1 = static_cast<int*>(vec[0]);
NonTrivial* data1 = static_cast<NonTrivial*>(vec[1]);


The problem is that I want to access special_data in the non-trivial case:



// Pretty sure this cast is valid! (famous last words)
std::vector<double>* special = static_cast<special_block<NonTrivial>*>(
static_cast<memory_block<NonTrivial>*>(vec[1]) // (1)
);



So now, the question



The problem arise at line (1): I have a pointer to data (of type NonTrivial), which is a member of memory_block<NonTrivial>. I know that the void* will always point to the first data member of a memory_block<T>.



So is casting a void* to the first member of a class into the class safe? If not, is there another way to do it? If it can make things simpler, I can get rid of the inheritance.



Also, I have no problem using std::aligned_storage in this case. If that can solve the problem, I'll use that.



I hoped standard layout would help me in this case, but my static assert seem to fail.



My static assert:



static_assert(
std::is_standard_layout<special_block<NonTrivial>>::value,
"Not standard layout don't assume anything about the layout"
);









share|improve this question
























  • Well technically I believe the compiler decides where to put member variables and how to align them. I'm not sure if you could assume it is a guarantee. You could add a static_assert that checks sizeof(memory_block<T>) == sizeof(T) that could give you a guarantee :-)

    – Neijwiert
    May 2 at 14:00












  • @Neijwiert yes and no. There is some guarantees the stardard make.

    – Guillaume Racicot
    May 2 at 14:01







  • 3





    For standard layout types the first member is the address of the class. After that we really have no other guarantees except that members are laid out in memory in the order they are declared, but there can/will be padding between them.

    – NathanOliver
    May 2 at 14:05






  • 1





    @FrançoisAndrieux The type itself isn't polymorphic, only a member is. Sometimes.

    – Deduplicator
    May 2 at 14:09







  • 1





    If you can upgrade to C++17 you could use std::any and the visitor pattern with std::visit to handle the type erasure and access for you.

    – NathanOliver
    May 2 at 14:14

















13















I have some code that look like this:



template<typename T>
struct memory_block
// Very not copiable, this class cannot move
memory_block(memory_block const&) = delete;
memory_block(memory_block const&&) = delete;
memory_block(memory_block&) = delete;
memory_block(memory_block&&) = delete;
memory_block& operator=(memory_block const&) = delete;
memory_block& operator=(memory_block&&) = delete;

// The only constructor construct the `data` member with args
template<typename... Args>
explicit memory_block(Args&&... args) noexcept :
datastd::forward<Args>(args)...

T data;
;

template<typename T>
struct special_block : memory_block<T>
using memory_block<T>::memory_block;
std::vector<double> special_data;
;

// There is no other inheritance. The hierarchy ends here.


Now I have to store these types into type erased storage. I chose a vector of void* as my container. I insert pointers of the data member into the vector:



struct NonTrivial virtual ~NonTrivial() ;

// exposed to other code
std::vector<void*> vec;

// My code use dynamic memory instead of static
// Data, but it's simpler to show it that way.
static memory_block<int> data0;
static special_block<NonTrivial> data1;

void add_stuff_into_vec()
// Add pointer to `data` member to the vector.
vec.emplace_back(&(data0->data));
vec.emplace_back(&(data1->data));



Then later in the code, I access the data:



// Yay everything is fine, I cast the void* to it original type
int* data1 = static_cast<int*>(vec[0]);
NonTrivial* data1 = static_cast<NonTrivial*>(vec[1]);


The problem is that I want to access special_data in the non-trivial case:



// Pretty sure this cast is valid! (famous last words)
std::vector<double>* special = static_cast<special_block<NonTrivial>*>(
static_cast<memory_block<NonTrivial>*>(vec[1]) // (1)
);



So now, the question



The problem arise at line (1): I have a pointer to data (of type NonTrivial), which is a member of memory_block<NonTrivial>. I know that the void* will always point to the first data member of a memory_block<T>.



So is casting a void* to the first member of a class into the class safe? If not, is there another way to do it? If it can make things simpler, I can get rid of the inheritance.



Also, I have no problem using std::aligned_storage in this case. If that can solve the problem, I'll use that.



I hoped standard layout would help me in this case, but my static assert seem to fail.



My static assert:



static_assert(
std::is_standard_layout<special_block<NonTrivial>>::value,
"Not standard layout don't assume anything about the layout"
);









share|improve this question
























  • Well technically I believe the compiler decides where to put member variables and how to align them. I'm not sure if you could assume it is a guarantee. You could add a static_assert that checks sizeof(memory_block<T>) == sizeof(T) that could give you a guarantee :-)

    – Neijwiert
    May 2 at 14:00












  • @Neijwiert yes and no. There is some guarantees the stardard make.

    – Guillaume Racicot
    May 2 at 14:01







  • 3





    For standard layout types the first member is the address of the class. After that we really have no other guarantees except that members are laid out in memory in the order they are declared, but there can/will be padding between them.

    – NathanOliver
    May 2 at 14:05






  • 1





    @FrançoisAndrieux The type itself isn't polymorphic, only a member is. Sometimes.

    – Deduplicator
    May 2 at 14:09







  • 1





    If you can upgrade to C++17 you could use std::any and the visitor pattern with std::visit to handle the type erasure and access for you.

    – NathanOliver
    May 2 at 14:14













13












13








13


1






I have some code that look like this:



template<typename T>
struct memory_block
// Very not copiable, this class cannot move
memory_block(memory_block const&) = delete;
memory_block(memory_block const&&) = delete;
memory_block(memory_block&) = delete;
memory_block(memory_block&&) = delete;
memory_block& operator=(memory_block const&) = delete;
memory_block& operator=(memory_block&&) = delete;

// The only constructor construct the `data` member with args
template<typename... Args>
explicit memory_block(Args&&... args) noexcept :
datastd::forward<Args>(args)...

T data;
;

template<typename T>
struct special_block : memory_block<T>
using memory_block<T>::memory_block;
std::vector<double> special_data;
;

// There is no other inheritance. The hierarchy ends here.


Now I have to store these types into type erased storage. I chose a vector of void* as my container. I insert pointers of the data member into the vector:



struct NonTrivial virtual ~NonTrivial() ;

// exposed to other code
std::vector<void*> vec;

// My code use dynamic memory instead of static
// Data, but it's simpler to show it that way.
static memory_block<int> data0;
static special_block<NonTrivial> data1;

void add_stuff_into_vec()
// Add pointer to `data` member to the vector.
vec.emplace_back(&(data0->data));
vec.emplace_back(&(data1->data));



Then later in the code, I access the data:



// Yay everything is fine, I cast the void* to it original type
int* data1 = static_cast<int*>(vec[0]);
NonTrivial* data1 = static_cast<NonTrivial*>(vec[1]);


The problem is that I want to access special_data in the non-trivial case:



// Pretty sure this cast is valid! (famous last words)
std::vector<double>* special = static_cast<special_block<NonTrivial>*>(
static_cast<memory_block<NonTrivial>*>(vec[1]) // (1)
);



So now, the question



The problem arise at line (1): I have a pointer to data (of type NonTrivial), which is a member of memory_block<NonTrivial>. I know that the void* will always point to the first data member of a memory_block<T>.



So is casting a void* to the first member of a class into the class safe? If not, is there another way to do it? If it can make things simpler, I can get rid of the inheritance.



Also, I have no problem using std::aligned_storage in this case. If that can solve the problem, I'll use that.



I hoped standard layout would help me in this case, but my static assert seem to fail.



My static assert:



static_assert(
std::is_standard_layout<special_block<NonTrivial>>::value,
"Not standard layout don't assume anything about the layout"
);









share|improve this question
















I have some code that look like this:



template<typename T>
struct memory_block
// Very not copiable, this class cannot move
memory_block(memory_block const&) = delete;
memory_block(memory_block const&&) = delete;
memory_block(memory_block&) = delete;
memory_block(memory_block&&) = delete;
memory_block& operator=(memory_block const&) = delete;
memory_block& operator=(memory_block&&) = delete;

// The only constructor construct the `data` member with args
template<typename... Args>
explicit memory_block(Args&&... args) noexcept :
datastd::forward<Args>(args)...

T data;
;

template<typename T>
struct special_block : memory_block<T>
using memory_block<T>::memory_block;
std::vector<double> special_data;
;

// There is no other inheritance. The hierarchy ends here.


Now I have to store these types into type erased storage. I chose a vector of void* as my container. I insert pointers of the data member into the vector:



struct NonTrivial virtual ~NonTrivial() ;

// exposed to other code
std::vector<void*> vec;

// My code use dynamic memory instead of static
// Data, but it's simpler to show it that way.
static memory_block<int> data0;
static special_block<NonTrivial> data1;

void add_stuff_into_vec()
// Add pointer to `data` member to the vector.
vec.emplace_back(&(data0->data));
vec.emplace_back(&(data1->data));



Then later in the code, I access the data:



// Yay everything is fine, I cast the void* to it original type
int* data1 = static_cast<int*>(vec[0]);
NonTrivial* data1 = static_cast<NonTrivial*>(vec[1]);


The problem is that I want to access special_data in the non-trivial case:



// Pretty sure this cast is valid! (famous last words)
std::vector<double>* special = static_cast<special_block<NonTrivial>*>(
static_cast<memory_block<NonTrivial>*>(vec[1]) // (1)
);



So now, the question



The problem arise at line (1): I have a pointer to data (of type NonTrivial), which is a member of memory_block<NonTrivial>. I know that the void* will always point to the first data member of a memory_block<T>.



So is casting a void* to the first member of a class into the class safe? If not, is there another way to do it? If it can make things simpler, I can get rid of the inheritance.



Also, I have no problem using std::aligned_storage in this case. If that can solve the problem, I'll use that.



I hoped standard layout would help me in this case, but my static assert seem to fail.



My static assert:



static_assert(
std::is_standard_layout<special_block<NonTrivial>>::value,
"Not standard layout don't assume anything about the layout"
);






c++ c++11 casting void-pointers






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 2 at 15:54







Guillaume Racicot

















asked May 2 at 13:55









Guillaume RacicotGuillaume Racicot

16.9k53874




16.9k53874












  • Well technically I believe the compiler decides where to put member variables and how to align them. I'm not sure if you could assume it is a guarantee. You could add a static_assert that checks sizeof(memory_block<T>) == sizeof(T) that could give you a guarantee :-)

    – Neijwiert
    May 2 at 14:00












  • @Neijwiert yes and no. There is some guarantees the stardard make.

    – Guillaume Racicot
    May 2 at 14:01







  • 3





    For standard layout types the first member is the address of the class. After that we really have no other guarantees except that members are laid out in memory in the order they are declared, but there can/will be padding between them.

    – NathanOliver
    May 2 at 14:05






  • 1





    @FrançoisAndrieux The type itself isn't polymorphic, only a member is. Sometimes.

    – Deduplicator
    May 2 at 14:09







  • 1





    If you can upgrade to C++17 you could use std::any and the visitor pattern with std::visit to handle the type erasure and access for you.

    – NathanOliver
    May 2 at 14:14

















  • Well technically I believe the compiler decides where to put member variables and how to align them. I'm not sure if you could assume it is a guarantee. You could add a static_assert that checks sizeof(memory_block<T>) == sizeof(T) that could give you a guarantee :-)

    – Neijwiert
    May 2 at 14:00












  • @Neijwiert yes and no. There is some guarantees the stardard make.

    – Guillaume Racicot
    May 2 at 14:01







  • 3





    For standard layout types the first member is the address of the class. After that we really have no other guarantees except that members are laid out in memory in the order they are declared, but there can/will be padding between them.

    – NathanOliver
    May 2 at 14:05






  • 1





    @FrançoisAndrieux The type itself isn't polymorphic, only a member is. Sometimes.

    – Deduplicator
    May 2 at 14:09







  • 1





    If you can upgrade to C++17 you could use std::any and the visitor pattern with std::visit to handle the type erasure and access for you.

    – NathanOliver
    May 2 at 14:14
















Well technically I believe the compiler decides where to put member variables and how to align them. I'm not sure if you could assume it is a guarantee. You could add a static_assert that checks sizeof(memory_block<T>) == sizeof(T) that could give you a guarantee :-)

– Neijwiert
May 2 at 14:00






Well technically I believe the compiler decides where to put member variables and how to align them. I'm not sure if you could assume it is a guarantee. You could add a static_assert that checks sizeof(memory_block<T>) == sizeof(T) that could give you a guarantee :-)

– Neijwiert
May 2 at 14:00














@Neijwiert yes and no. There is some guarantees the stardard make.

– Guillaume Racicot
May 2 at 14:01






@Neijwiert yes and no. There is some guarantees the stardard make.

– Guillaume Racicot
May 2 at 14:01





3




3





For standard layout types the first member is the address of the class. After that we really have no other guarantees except that members are laid out in memory in the order they are declared, but there can/will be padding between them.

– NathanOliver
May 2 at 14:05





For standard layout types the first member is the address of the class. After that we really have no other guarantees except that members are laid out in memory in the order they are declared, but there can/will be padding between them.

– NathanOliver
May 2 at 14:05




1




1





@FrançoisAndrieux The type itself isn't polymorphic, only a member is. Sometimes.

– Deduplicator
May 2 at 14:09






@FrançoisAndrieux The type itself isn't polymorphic, only a member is. Sometimes.

– Deduplicator
May 2 at 14:09





1




1





If you can upgrade to C++17 you could use std::any and the visitor pattern with std::visit to handle the type erasure and access for you.

– NathanOliver
May 2 at 14:14





If you can upgrade to C++17 you could use std::any and the visitor pattern with std::visit to handle the type erasure and access for you.

– NathanOliver
May 2 at 14:14












1 Answer
1






active

oldest

votes


















14














As long as memory_block<T> is a standard-layout type [class.prop]/3, the address of a memory_block<T> and the address of its first member data are pointer interconvertible [basic.compound]/4.3. If this is the case, the standard guarantees that you can reinterpret_cast to get a pointer to one from a pointer to the other. As soon as you don't have a standard-layout type, there is no such guarantee.



For your particular case, memory_block<T> will be standard-layout as long as T is standard-layout. Your special_block will never be standard layout because it contains an std::vector (as also pointed out by @NathanOliver in his comment below), which is not guaranteed to be standard layout. In your case, since you just insert a pointer to the data member of the memory_block<T> subobject of your special_block<T>, you could still make that work as long as T is standard-layout if you reinterpret_cast your void* back to memory_block<T>* and then static_cast that to special_block<T>* (assuming that you know for sure that the dynamic type of the complete object is actually special_block<T>). Unfortunately, as soon as NonTrivial enters the picture, all bets are off because NonTrivial has a virtual method and, thus, is not standard layout which also means that memory_block<NonTrivial> will not be standard layout…



One thing you could do is, e.g., have just a buffer to provide storage for a T in your memory_block and then construct the actual T inside the storage of data via placement new. for example:



#include <utility>
#include <new>

template <typename T>
struct memory_block

alignas(T) char data[sizeof(T)];

template <typename... Args>
explicit memory_block(Args&&... args) noexcept(noexcept(new (data) T(std::forward<Args>(args)...)))

new (data) T(std::forward<Args>(args)...);


~memory_block()

std::launder(reinterpret_cast<T*>(data))->~T();



;


That way memory_block<T> will always be standard-layout…






share|improve this answer

























  • I made some tests and it seem memory_block<T> is okay, but not special_block<T>. Am I still okay if I cast the pointer to a memory_block<T> before?

    – Guillaume Racicot
    May 2 at 14:10






  • 1





    Does this mean you would have to first static_cast<NonTrivial*>(vec[1]) before you then reinterpret_cast<memory_block<NonTrivial>*>?

    – Max Langhof
    May 2 at 14:10






  • 1





    @GuillaumeRacicot memory_block<T> is only standard layout iff T is standard layout. Since NonTrivial is not standard layout (it has a virtual function), casting from NonTrivial* to memory_block<NonTrivial>* is not allowed. Going from memory_block<NonTrivial>* to special_block<NonTrivial>* is not relevant to the issue. Or at least I don't see how.

    – Max Langhof
    May 2 at 14:11












  • Might also want to point out that special_block is never standard layout since it contains a vector.

    – NathanOliver
    May 2 at 14:15






  • 1





    @NathanOliver And because it has non-static members both in itself and in its base class.

    – Max Langhof
    May 2 at 14:15












Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55954067%2fis-interpreting-a-pointer-to-first-member-as-the-class-itself-well-defined%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









14














As long as memory_block<T> is a standard-layout type [class.prop]/3, the address of a memory_block<T> and the address of its first member data are pointer interconvertible [basic.compound]/4.3. If this is the case, the standard guarantees that you can reinterpret_cast to get a pointer to one from a pointer to the other. As soon as you don't have a standard-layout type, there is no such guarantee.



For your particular case, memory_block<T> will be standard-layout as long as T is standard-layout. Your special_block will never be standard layout because it contains an std::vector (as also pointed out by @NathanOliver in his comment below), which is not guaranteed to be standard layout. In your case, since you just insert a pointer to the data member of the memory_block<T> subobject of your special_block<T>, you could still make that work as long as T is standard-layout if you reinterpret_cast your void* back to memory_block<T>* and then static_cast that to special_block<T>* (assuming that you know for sure that the dynamic type of the complete object is actually special_block<T>). Unfortunately, as soon as NonTrivial enters the picture, all bets are off because NonTrivial has a virtual method and, thus, is not standard layout which also means that memory_block<NonTrivial> will not be standard layout…



One thing you could do is, e.g., have just a buffer to provide storage for a T in your memory_block and then construct the actual T inside the storage of data via placement new. for example:



#include <utility>
#include <new>

template <typename T>
struct memory_block

alignas(T) char data[sizeof(T)];

template <typename... Args>
explicit memory_block(Args&&... args) noexcept(noexcept(new (data) T(std::forward<Args>(args)...)))

new (data) T(std::forward<Args>(args)...);


~memory_block()

std::launder(reinterpret_cast<T*>(data))->~T();



;


That way memory_block<T> will always be standard-layout…






share|improve this answer

























  • I made some tests and it seem memory_block<T> is okay, but not special_block<T>. Am I still okay if I cast the pointer to a memory_block<T> before?

    – Guillaume Racicot
    May 2 at 14:10






  • 1





    Does this mean you would have to first static_cast<NonTrivial*>(vec[1]) before you then reinterpret_cast<memory_block<NonTrivial>*>?

    – Max Langhof
    May 2 at 14:10






  • 1





    @GuillaumeRacicot memory_block<T> is only standard layout iff T is standard layout. Since NonTrivial is not standard layout (it has a virtual function), casting from NonTrivial* to memory_block<NonTrivial>* is not allowed. Going from memory_block<NonTrivial>* to special_block<NonTrivial>* is not relevant to the issue. Or at least I don't see how.

    – Max Langhof
    May 2 at 14:11












  • Might also want to point out that special_block is never standard layout since it contains a vector.

    – NathanOliver
    May 2 at 14:15






  • 1





    @NathanOliver And because it has non-static members both in itself and in its base class.

    – Max Langhof
    May 2 at 14:15
















14














As long as memory_block<T> is a standard-layout type [class.prop]/3, the address of a memory_block<T> and the address of its first member data are pointer interconvertible [basic.compound]/4.3. If this is the case, the standard guarantees that you can reinterpret_cast to get a pointer to one from a pointer to the other. As soon as you don't have a standard-layout type, there is no such guarantee.



For your particular case, memory_block<T> will be standard-layout as long as T is standard-layout. Your special_block will never be standard layout because it contains an std::vector (as also pointed out by @NathanOliver in his comment below), which is not guaranteed to be standard layout. In your case, since you just insert a pointer to the data member of the memory_block<T> subobject of your special_block<T>, you could still make that work as long as T is standard-layout if you reinterpret_cast your void* back to memory_block<T>* and then static_cast that to special_block<T>* (assuming that you know for sure that the dynamic type of the complete object is actually special_block<T>). Unfortunately, as soon as NonTrivial enters the picture, all bets are off because NonTrivial has a virtual method and, thus, is not standard layout which also means that memory_block<NonTrivial> will not be standard layout…



One thing you could do is, e.g., have just a buffer to provide storage for a T in your memory_block and then construct the actual T inside the storage of data via placement new. for example:



#include <utility>
#include <new>

template <typename T>
struct memory_block

alignas(T) char data[sizeof(T)];

template <typename... Args>
explicit memory_block(Args&&... args) noexcept(noexcept(new (data) T(std::forward<Args>(args)...)))

new (data) T(std::forward<Args>(args)...);


~memory_block()

std::launder(reinterpret_cast<T*>(data))->~T();



;


That way memory_block<T> will always be standard-layout…






share|improve this answer

























  • I made some tests and it seem memory_block<T> is okay, but not special_block<T>. Am I still okay if I cast the pointer to a memory_block<T> before?

    – Guillaume Racicot
    May 2 at 14:10






  • 1





    Does this mean you would have to first static_cast<NonTrivial*>(vec[1]) before you then reinterpret_cast<memory_block<NonTrivial>*>?

    – Max Langhof
    May 2 at 14:10






  • 1





    @GuillaumeRacicot memory_block<T> is only standard layout iff T is standard layout. Since NonTrivial is not standard layout (it has a virtual function), casting from NonTrivial* to memory_block<NonTrivial>* is not allowed. Going from memory_block<NonTrivial>* to special_block<NonTrivial>* is not relevant to the issue. Or at least I don't see how.

    – Max Langhof
    May 2 at 14:11












  • Might also want to point out that special_block is never standard layout since it contains a vector.

    – NathanOliver
    May 2 at 14:15






  • 1





    @NathanOliver And because it has non-static members both in itself and in its base class.

    – Max Langhof
    May 2 at 14:15














14












14








14







As long as memory_block<T> is a standard-layout type [class.prop]/3, the address of a memory_block<T> and the address of its first member data are pointer interconvertible [basic.compound]/4.3. If this is the case, the standard guarantees that you can reinterpret_cast to get a pointer to one from a pointer to the other. As soon as you don't have a standard-layout type, there is no such guarantee.



For your particular case, memory_block<T> will be standard-layout as long as T is standard-layout. Your special_block will never be standard layout because it contains an std::vector (as also pointed out by @NathanOliver in his comment below), which is not guaranteed to be standard layout. In your case, since you just insert a pointer to the data member of the memory_block<T> subobject of your special_block<T>, you could still make that work as long as T is standard-layout if you reinterpret_cast your void* back to memory_block<T>* and then static_cast that to special_block<T>* (assuming that you know for sure that the dynamic type of the complete object is actually special_block<T>). Unfortunately, as soon as NonTrivial enters the picture, all bets are off because NonTrivial has a virtual method and, thus, is not standard layout which also means that memory_block<NonTrivial> will not be standard layout…



One thing you could do is, e.g., have just a buffer to provide storage for a T in your memory_block and then construct the actual T inside the storage of data via placement new. for example:



#include <utility>
#include <new>

template <typename T>
struct memory_block

alignas(T) char data[sizeof(T)];

template <typename... Args>
explicit memory_block(Args&&... args) noexcept(noexcept(new (data) T(std::forward<Args>(args)...)))

new (data) T(std::forward<Args>(args)...);


~memory_block()

std::launder(reinterpret_cast<T*>(data))->~T();



;


That way memory_block<T> will always be standard-layout…






share|improve this answer















As long as memory_block<T> is a standard-layout type [class.prop]/3, the address of a memory_block<T> and the address of its first member data are pointer interconvertible [basic.compound]/4.3. If this is the case, the standard guarantees that you can reinterpret_cast to get a pointer to one from a pointer to the other. As soon as you don't have a standard-layout type, there is no such guarantee.



For your particular case, memory_block<T> will be standard-layout as long as T is standard-layout. Your special_block will never be standard layout because it contains an std::vector (as also pointed out by @NathanOliver in his comment below), which is not guaranteed to be standard layout. In your case, since you just insert a pointer to the data member of the memory_block<T> subobject of your special_block<T>, you could still make that work as long as T is standard-layout if you reinterpret_cast your void* back to memory_block<T>* and then static_cast that to special_block<T>* (assuming that you know for sure that the dynamic type of the complete object is actually special_block<T>). Unfortunately, as soon as NonTrivial enters the picture, all bets are off because NonTrivial has a virtual method and, thus, is not standard layout which also means that memory_block<NonTrivial> will not be standard layout…



One thing you could do is, e.g., have just a buffer to provide storage for a T in your memory_block and then construct the actual T inside the storage of data via placement new. for example:



#include <utility>
#include <new>

template <typename T>
struct memory_block

alignas(T) char data[sizeof(T)];

template <typename... Args>
explicit memory_block(Args&&... args) noexcept(noexcept(new (data) T(std::forward<Args>(args)...)))

new (data) T(std::forward<Args>(args)...);


~memory_block()

std::launder(reinterpret_cast<T*>(data))->~T();



;


That way memory_block<T> will always be standard-layout…







share|improve this answer














share|improve this answer



share|improve this answer








edited May 2 at 15:01

























answered May 2 at 14:06









Michael KenzelMichael Kenzel

9,36311826




9,36311826












  • I made some tests and it seem memory_block<T> is okay, but not special_block<T>. Am I still okay if I cast the pointer to a memory_block<T> before?

    – Guillaume Racicot
    May 2 at 14:10






  • 1





    Does this mean you would have to first static_cast<NonTrivial*>(vec[1]) before you then reinterpret_cast<memory_block<NonTrivial>*>?

    – Max Langhof
    May 2 at 14:10






  • 1





    @GuillaumeRacicot memory_block<T> is only standard layout iff T is standard layout. Since NonTrivial is not standard layout (it has a virtual function), casting from NonTrivial* to memory_block<NonTrivial>* is not allowed. Going from memory_block<NonTrivial>* to special_block<NonTrivial>* is not relevant to the issue. Or at least I don't see how.

    – Max Langhof
    May 2 at 14:11












  • Might also want to point out that special_block is never standard layout since it contains a vector.

    – NathanOliver
    May 2 at 14:15






  • 1





    @NathanOliver And because it has non-static members both in itself and in its base class.

    – Max Langhof
    May 2 at 14:15


















  • I made some tests and it seem memory_block<T> is okay, but not special_block<T>. Am I still okay if I cast the pointer to a memory_block<T> before?

    – Guillaume Racicot
    May 2 at 14:10






  • 1





    Does this mean you would have to first static_cast<NonTrivial*>(vec[1]) before you then reinterpret_cast<memory_block<NonTrivial>*>?

    – Max Langhof
    May 2 at 14:10






  • 1





    @GuillaumeRacicot memory_block<T> is only standard layout iff T is standard layout. Since NonTrivial is not standard layout (it has a virtual function), casting from NonTrivial* to memory_block<NonTrivial>* is not allowed. Going from memory_block<NonTrivial>* to special_block<NonTrivial>* is not relevant to the issue. Or at least I don't see how.

    – Max Langhof
    May 2 at 14:11












  • Might also want to point out that special_block is never standard layout since it contains a vector.

    – NathanOliver
    May 2 at 14:15






  • 1





    @NathanOliver And because it has non-static members both in itself and in its base class.

    – Max Langhof
    May 2 at 14:15

















I made some tests and it seem memory_block<T> is okay, but not special_block<T>. Am I still okay if I cast the pointer to a memory_block<T> before?

– Guillaume Racicot
May 2 at 14:10





I made some tests and it seem memory_block<T> is okay, but not special_block<T>. Am I still okay if I cast the pointer to a memory_block<T> before?

– Guillaume Racicot
May 2 at 14:10




1




1





Does this mean you would have to first static_cast<NonTrivial*>(vec[1]) before you then reinterpret_cast<memory_block<NonTrivial>*>?

– Max Langhof
May 2 at 14:10





Does this mean you would have to first static_cast<NonTrivial*>(vec[1]) before you then reinterpret_cast<memory_block<NonTrivial>*>?

– Max Langhof
May 2 at 14:10




1




1





@GuillaumeRacicot memory_block<T> is only standard layout iff T is standard layout. Since NonTrivial is not standard layout (it has a virtual function), casting from NonTrivial* to memory_block<NonTrivial>* is not allowed. Going from memory_block<NonTrivial>* to special_block<NonTrivial>* is not relevant to the issue. Or at least I don't see how.

– Max Langhof
May 2 at 14:11






@GuillaumeRacicot memory_block<T> is only standard layout iff T is standard layout. Since NonTrivial is not standard layout (it has a virtual function), casting from NonTrivial* to memory_block<NonTrivial>* is not allowed. Going from memory_block<NonTrivial>* to special_block<NonTrivial>* is not relevant to the issue. Or at least I don't see how.

– Max Langhof
May 2 at 14:11














Might also want to point out that special_block is never standard layout since it contains a vector.

– NathanOliver
May 2 at 14:15





Might also want to point out that special_block is never standard layout since it contains a vector.

– NathanOliver
May 2 at 14:15




1




1





@NathanOliver And because it has non-static members both in itself and in its base class.

– Max Langhof
May 2 at 14:15






@NathanOliver And because it has non-static members both in itself and in its base class.

– Max Langhof
May 2 at 14:15




















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55954067%2fis-interpreting-a-pointer-to-first-member-as-the-class-itself-well-defined%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Get product attribute by attribute group code in magento 2get product attribute by product attribute group in magento 2Magento 2 Log Bundle Product Data in List Page?How to get all product attribute of a attribute group of Default attribute set?Magento 2.1 Create a filter in the product grid by new attributeMagento 2 : Get Product Attribute values By GroupMagento 2 How to get all existing values for one attributeMagento 2 get custom attribute of a single product inside a pluginMagento 2.3 How to get all the Multi Source Inventory (MSI) locations collection in custom module?Magento2: how to develop rest API to get new productsGet product attribute by attribute group code ( [attribute_group_code] ) in magento 2

Category:9 (number) SubcategoriesMedia in category "9 (number)"Navigation menuUpload mediaGND ID: 4485639-8Library of Congress authority ID: sh85091979ReasonatorScholiaStatistics

Magento 2.3: How do i solve this, Not registered handle, on custom form?How can i rewrite TierPrice Block in Magento2magento 2 captcha not rendering if I override layout xmlmain.CRITICAL: Plugin class doesn't existMagento 2 : Problem while adding custom button order view page?Magento 2.2.5: Overriding Admin Controller sales/orderMagento 2.2.5: Add, Update and Delete existing products Custom OptionsMagento 2.3 : File Upload issue in UI Component FormMagento2 Not registered handleHow to configured Form Builder Js in my custom magento 2.3.0 module?Magento 2.3. How to create image upload field in an admin form