I was looking through some of the standard library's implementation for the usual containers (vector, unordered_map, etc...) when I came across the following, in the xutility header:
template <class _CtgIt, class _OutCtgIt>
_OutCtgIt _Copy_memmove(_CtgIt _First, _CtgIt _Last, _OutCtgIt _Dest) {
auto _FirstPtr = _To_address(_First);
auto _LastPtr = _To_address(_Last);
auto _DestPtr = _To_address(_Dest);
const char* const _First_ch = const_cast<const char*>(reinterpret_cast<const volatile char*>(_FirstPtr));
const char* const _Last_ch = const_cast<const char*>(reinterpret_cast<const volatile char*>(_LastPtr));
char* const _Dest_ch = const_cast<char*>(reinterpret_cast<const volatile char*>(_DestPtr));
const auto _Count = static_cast<size_t>(_Last_ch - _First_ch);
_CSTD memmove(_Dest_ch, _First_ch, _Count);
if constexpr (is_pointer_v<_OutCtgIt>) {
return reinterpret_cast<_OutCtgIt>(_Dest_ch + _Count);
} else {
return _Dest + (_LastPtr - _FirstPtr);
}
}
Does anybody know why _First_ch and _Last_ch are first cast to const volatile char* type then immediately cast to const char*? I'm assuming it's to stop the compiler from optimizing prematurely, for some specific cases, but no concrete examples come to mind.
If the target type of the pointer is volatile-qualified, it is not possible to use reinterpret_cast to directly cast to const char*.
reinterpret_cast is not allowed to cast away const or volatile. const_cast however can do this, while not being able to change the pointer's target type itself.
I think a C-style cast would also always work in this situation, but reasoning about it is a bit more difficult, since it attempts multiple C++-style conversion sequences, only the last of which is a reinterpret_cast followed by a const_cast.
It may be just a style choice to not use C-style casts here.
Related
I'm trying to reimplement memchr as constexpr (1). I haven't expected issues as I have already successfully done the same thing with strchr which is very simmilar.
However both clang and gcc refuse to cast const void* to anything else within constexpr function, which prevents me to access the actual values.
I understand that working with void* in constexpr function is weird, as we cannot do malloc and there is no way to specify arbitrary data as literal values. I'm doing this basically as a part of an excercise to rewrite as much as I can from as constexpr (2).
Still I'd like to know why this is not allowed and if there is any way around it.
Thank you!
(1) My implementation of memchr:
constexpr void const *memchr(const void *ptr, int ch, size_t count) {
const auto block_address = static_cast<const uint8_t *>(ptr);
const auto needle = static_cast<uint8_t>(ch);
for (uintptr_t pos{0}; pos < count; ++pos) {
auto byte_address = block_address + pos;
const uint8_t value = *byte_address;
if (needle == value) {
return static_cast<void const *>(byte_address);
}
}
return nullptr;
}
(2) The entire project on Github: https://github.com/jlanik/constexprstring
No, it is impossible to use void* in such a way in constant expressions. Casts from void* to other object pointer types are forbidden in constant expressions. reinterpret_cast is forbidden as well.
This is probably intentional to make it impossible to access the object representation at compile-time.
You cannot have a memchr with its usual signature at compile-time.
The best that I think you can do is write the function for pointers to char and its cv-qualified versions, as well as std::byte (either as overloads or as template), instead of void*.
For pointers to objects of other types it is going to be tricky in some cases and impossible in most cases to implement the exact semantics of memchr.
While I am not certain that it is possible, maybe, in a templated version of memchr, one can read the underlying bytes of the objects passed-by-pointer via a std::bit_cast into a struct containing a std::byte/unsigned char array of appropriate size.
I have seen const used twice in the declaration of a static array before and now that I am creating my own static array I am wondering why const would be needed twice in some situations.
Does having an array of pointers make a difference?
a. static const TYPE name[5];
b. static const TYPE const name[5];
c. static const TYPE* name[5];
d. static const TYPE* const name[5];
My understanding is that b. is invalid, but if using const twice is valid, what is its purpose?
const TYPE* x;
Means that the thing that x points at is const.
TYPE* const x;
Means that the pointer x is const.
Combining the 2 you get:
const TYPE* const x;
Meaning the pointer and the thing pointed to are both const.
You can apply any cv-qualifier (const or volatile) to any type, including cv-qualified types -- yet not in the same declaration. However, they bind more strongly than any operator, in terms of precedence and can be applied on both sides of the qualified type:
// Let T by any type:
T const tr;
const T tl;
const T const tlr; // only in C
const const const const const T t5; // only in C
typedef const T CT;
CT const tcc; // fine, although CT was already const
declare exactly the same, a constant T. If T already has cv-qualifiers, this doesn't change the meaning of additional qualification.
Now, to the precedence; You can say "I want a pointer to a constant T":
const T (* tp);
which is usually written as
const T* tp;
because the const binds stronger than the * anyway. In the same pattern, you can define a variable that is "constant but points at a mutable T":
T (* const tp) = 0; // must be initialised, because tp is immutable
which is commonly written as
T* const tp = 0;
In the same vein the subscript operator [] is applied -- with the same precedence as in expressions.
In the first code block you have a redundant duplicate const in the second line, which has no effect. (In fact, good compilers will warn you about this.) You're declaring an array of 5 const TYPEs, that's it.
The second code block has two different scenarios: The first line makes an array of five mutable pointers to const TYPEs, while the latter makes an array of five constant pointers to const TYPEs.
Note that you must initialize an array of constants: Since you can't change the values later, it doesn't make sense to define them uninitialized.
Using const twice on a type is illegal in C++ 2003 but legal in C++ 2011 (see 7.1.6.1 [decl.type.cv] paragraph 1: "Redundant cv-qualifications are ignored."). When you used
static const TYPE const name[5];
you made TYPE constant twice. Note, however, that this declaration is illegal in C++ 2011, too, because you need initialize a const object when declaring it. The meaning of
const TYPE
and
TYPE const
is absolutely equivalent: In both cases you make the TYPE object constant. For consistency, I always put the const to the right because every except for the top-level type the const has to be put on the right side (well, unless some coding guideline mandates differently but I'm fighting silly coding guidelines).
When using pointers, thinks become different. There are two types involved: type pointed to type and the pointer. Each one of these can be made const separately:
TYPE const* ptr1(0); // non-const pointer to const TYPE
TYPE* const ptr2(0); // const pointer to non-const TYPE
TYPE const* const ptr3(0); // const pointer to const TYPE
The best way to figure out what is made const is to read the type declaration from right to left. Of course, this assumes to that const qualifiers are put into the right location. You can replace const by volatile or const volatile in the discussion above and the same reasoning applies.
I don't know why this simple code is not working:
int main()
{
const char* c = "ret";
typedef unsigned char GOK_UINT8;
typedef GOK_UINT8* pGOK_UINT8;
const pGOK_UINT8 y = reinterpret_cast<const GOK_UINT8*>(c);
return 0;
}
Can someone tell me why the reinterpret_cast does not work?
Can someone tell me why the reinterpret_cast should not work?
AFAICS, the reinterpret_cast should work fine, but the assignment afterwards should cause an error.
That's because a const GOK_UINT8* is a non-const pointer to const GOK_UINT8 objects, while a const pGOK_UINT8 is a const pointer to non-const objects.
The former protects the object referred to, the latter the pointer referring to the object. If the assignment would be allowed, you could then change the object that the const GOK_UINT8* meant to protect from changing.
Note that typedefed pointers behave strange that way. That's because of the strange declaration syntax of const in (C and thus also in) C++: A const protects the thing to its left, unless there isn't anything, then it protects the thing to its right. So in T const and in T const*, the object of type T is protected, while in T* const the pointer to an object of type T is protected. If you have
typedef T* TPtr;
then TPtr const again makes the pointer const. So does const TPtr. A typedefed pointer either points to const or non-const objects, you can't change that. You can't stuff a const into the vicinity of TPtr and expect that to protect the objects the pointer refers to.
(BTW, this is why STL classes have to define both an iterator and a const_iterator.)
Yep sbi is correct.
Modified your code accordingly,
const char* c = "ret";
typedef unsigned char GOK_UINT8;
typedef const GOK_UINT8* pGOK_UINT8;
pGOK_UINT8 y = reinterpret_cast<const GOK_UINT8*>(c);
printf("%s", y);
In boost::detail::addressof_impl::f() a series of reinterpret_casts is done to obtain the actual address of the object in case class T has overloaded operator&():
template<class T> struct addressof_impl
{
static inline T* f( T& v, long )
{
return reinterpret_cast<T*>(
&const_cast<char&>(reinterpret_cast<const volatile char&>(v)));
}
}
What's the purpose of cast to const volatile char& instead of just casting to char&?
A cast straight to char& would fail if T has const or volatile qualifiers - reinterpret_cast can't remove these (but can add them), and const_cast can't make arbitrary type changes.
The object may be const or volatile, or both (as oxymoronic as that may be), in which case it is probably illegal to reinterpret_cast it to a type that lacks these attributes. (Going in the opposite direction is of course never a problem).
I can't find much information on const_cast. The only info I could find (on Stack Overflow) is:
The const_cast<>() is used to add/remove const(ness) (or volatile-ness) of a variable.
This makes me nervous. Could using a const_cast cause unexpected behavior? If so, what?
Alternatively, when is it okay to use const_cast?
const_cast is safe only if you're casting a variable that was originally non-const. For example, if you have a function that takes a parameter of a const char *, and you pass in a modifiable char *, it's safe to const_cast that parameter back to a char * and modify it. However, if the original variable was in fact const, then using const_cast will result in undefined behavior.
void func(const char *param, size_t sz, bool modify)
{
if(modify)
strncpy(const_cast<char *>(param), sz, "new string");
printf("param: %s\n", param);
}
...
char buffer[16];
const char *unmodifiable = "string constant";
func(buffer, sizeof(buffer), true); // OK
func(unmodifiable, strlen(unmodifiable), false); // OK
func(unmodifiable, strlen(unmodifiable), true); // UNDEFINED BEHAVIOR
I can think of two situations where const_cast is safe and useful (there may be other valid cases).
One is when you have a const instance, reference, or pointer, and you want to pass a pointer or reference to an API that is not const-correct, but that you're CERTAIN won't modify the object. You can const_cast the pointer and pass it to the API, trusting that it won't really change anything. For example:
void log(char* text); // Won't change text -- just const-incorrect
void my_func(const std::string& message)
{
log(const_cast<char*>(&message.c_str()));
}
The other is if you're using an older compiler that doesn't implement 'mutable', and you want to create a class that is logically const but not bitwise const. You can const_cast 'this' within a const method and modify members of your class.
class MyClass
{
char cached_data[10000]; // should be mutable
bool cache_dirty; // should also be mutable
public:
char getData(int index) const
{
if (cache_dirty)
{
MyClass* thisptr = const_cast<MyClass*>(this);
update_cache(thisptr->cached_data);
}
return cached_data[index];
}
};
I find it hard to believe that that's the only information you could find about const_cast. Quoting from the second Google hit:
If you cast away the constness of an
object that has been explicitly
declared as const, and attempt to
modify it, the results are undefined.
However, if you cast away the
constness of an object that has not
been explicitly declared as const, you
can modify it safely.
What Adam says. Another example where const_cast can be helpful:
struct sample {
T& getT() {
return const_cast<T&>(static_cast<const sample*>(this)->getT());
}
const T& getT() const {
/* possibly much code here */
return t;
}
T t;
};
We first add const to the type this points to, then we call the const version of getT, and then we remove const from the return type, which is valid since t must be non-const (otherwise, the non-const version of getT couldn't have been called). This can be very useful if you got a large function body and you want to avoid redundant code.
The short answer is no, it's not safe.
The long answer is that if you know enough to use it, then it should be safe.
When you're casting, what you are essentially saying is, "I know something the compiler doesn't know." In the case of const_cast, what you are saying is, "Even though this method takes in a non-const reference or pointer, I know that it won't change the parameter I pass it."
So if you do actually know what you are claiming to know in using the cast, then it's fine to use it.
You're destroying any chance at thread-safety, if you start modifying things that the compiler thought were const.