Looking at std::any implementation it is very strange why access through aligned_storage for small objects is implemented with const. What is the purpose of this? It is to do with something that aligned_storage may store const objects? If so where does the standard backs this up?
Link to the latest std::any implementation in libstdc++
https://github.com/gcc-mirror/gcc/blob/a90bd3ea6d1ba27b15476f0a768d7952c6723420/libstdc%2B%2B-v3/include/std/any#L392
static _Tp* _S_access(const _Storage& __storage)
{
// The contained object is in __storage._M_buffer
const void* __addr = &__storage._M_buffer;
return static_cast<_Tp*>(const_cast<void*>(__addr));
}
Appreciate any thoughts.
There is no trick here, it's just simplicity of implementation - to avoid code duplication.
You need both const and non-const versions of this function with essentially the same implementation. It's easy to write only one version and put const-correctness burden on a user - this is an internal function, so that user is a library implementer and they know what they are doing.
For both statically and dynamically allocated objects _S_access() takes __storage by const&, so that you could pass both const _Storage& and _Storage&.
For statically allocated objects,
static _Tp*
_S_access(const _Storage& __storage)
{
// The contained object is in __storage._M_buffer
const void* __addr = &__storage._M_buffer;
return static_cast<_Tp*>(const_cast<void*>(__addr));
}
when an address of _Storage's data member _M_buffer is taken, it automatically gets const qualification, so we need to cast it away.
For dynamically allocated ones,
static _Tp*
_S_access(const _Storage& __storage)
{
// The contained object is in *__storage._M_ptr
return static_cast<_Tp*>(__storage._M_ptr);
}
we read _M_ptr data member of type void*. No const is propagated into that void*, so no const_cast is needed. Const-correctness is still on a user.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With