How to Convert "Pointer to Pointer Type" to Const

How to convert pointer to pointer type to const?

The language allows implicit conversion from double ** to const double *const *, but not to const double **. The conversion you attempt would implicitly violate the rules of const correctness, even though it is not immediately obvious.

The example in the [de-facto standard] C++ FAQ illustrates the issue

https://isocpp.org/wiki/faq/const-correctness#constptrptr-conversion

Basically, the rule is: once you add const at some level of indirection, you have to add const to all levels of indirection all the way to the right. For example, int ***** cannot be implicitly converted to int **const ***, but it can be implicitly converted to int **const *const *const *

Why isn't it legal to convert pointer to pointer to non-const to a pointer to pointer to const

From the standard:

const char c = 'c';
char* pc;
const char** pcc = &pc; // not allowed
*pcc = &c;
*pc = 'C'; // would allow to modify a const object

Add const to pointer type

You can

fun(static_cast<std::conditional_t<
std::is_pointer_v<T>,
std::add_pointer_t<std::add_const_t<std::remove_pointer_t<T>>>,
std::add_const_t<T>
>
>(value));

Then when T is MyData*, the converted type would be MyData const*; for non-pointer type like MyData the converted type would be MyData const.

Implicit Pointer-To-Const-T conversion

A pointer to an object of type T is implicitely converted into a
pointer to an object of type const-T. Is this implicit conversion
somewhere defined in the C11 standard?

Yes. This implicit conversion is mandated by the standard.

Paragraph 3 of section 6.5.4 Cast Operators says that

Conversions that involve pointers, other than where permitted by the
constraints of 6.5.16.1, shall be specified by means of an explicit
cast.

and the referenced 6.5.16.1 under point 3 says:

the left operand has atomic, qualified, or unqualified pointer type,
and (considering the type the left operand would have after lvalue
conversion) both operands are pointers to qualified or unqualified
versions of compatible types, and the type pointed to by the left has
all the qualifiers of the type pointed to by the right;

Therefore the implicit conversion for const T *p = &x; holds because you're only adding qualifiers, not removing them.

const T **pp = &p; doesn't fall under this, so you need an explicit cast (C++ would allow const T*const*pp = &p; (the second const is needed) but C still wouldn't.)

The pointer conversion through an explicit cast isn't a problem as far as UB is concerned as long as the alignments match (which for pointers to differently qualified types they will) because
6.3.2.3p7 guarantees that:

A pointer to an object type may be converted to a pointer to a
different object type. If the resulting pointer is not correctly
aligned68) for the referenced type, the behavior is undefined.
Otherwise, when converted back again, the result shall compare equal
to the original pointer. When a pointer to an object is converted to a
pointer to a character type, the result points to the lowest addressed
byte of the object. Successive increments of the result, up to the
size of the object, yield pointers to the remaining bytes of the
object.

but you need to be mindful of accesses/dereferences which will be governed by the strict aliasing rule:

An object shall have its stored value accessed only by an lvalue
expression that has one of the following types:88)

a type compatible with the effective type of the object, a qualified
version of a type compatible with the effective type of the object, a
type that is the signed or unsigned type corresponding to the
effective type of the object, a type that is the signed or unsigned
type corresponding to a qualified version of the effective type of the
object, an aggregate or union type that includes one of the
aforementioned types among its members (including, recursively, a
member of a subaggregate or contained union), or a character type.

casting const pointers between different types

The way I understand it is that the underlying values of this array
can be changed but the pointer itself cannot be moved to point to
something else.

Nope. It means that you cannot change the entity this pointer points too, but you are able to change a pointer itself. To forbid changing the pointer you have to make the pointer itself const:

const char* const buffer;
^^^^^

How should this casting be performed?

The casting should be performed with reinterpret_cast.

Only the following conversions can be done with reinterpret_cast, except when such conversions would cast away constness or volatility.

...

5) Any pointer to object of type T1 can be converted to pointer to object of another type cv T2.

So you have to write:

unsigned short * const values = reinterpret_cast<unsigned short * const>(current);

or even:

decltype(auto) values = reinterpret_cast<unsigned short * const>(current);

Finally, static_cast is not applicable here because you try to perform a cast between different unrelated pointer types.



Related Topics



Leave a reply



Submit