Reputation: 30136
The following piece of code:
typedef void* ptr_t;
void func()
{
const ptr_t ptr; // Line 1
ptr = ...; // Line 2
}
Yields the following compilation errors:
Line 1, Error C2734 (C++): const
object must be initialized if not extern
Line 2, Error C3892 (C++): you cannot assign to a variable that is const
Line 2, Error C2166 (C): l-value specifies const
object
The reason behind these compilation errors:
const ptr_t ptr
is interpreted as void* const ptr
instead of const void* ptr
With void* const ptr
, you cannot change the pointer but you can change the pointed data
With const void* ptr
, you can change the pointer but you cannot change the pointed data
My goal here is to prevent possible attempts to change the contents of the memory pointed by ptr
.
I can work-around this problem using #define ptr_t void*
instead of typedef void* ptr_t
.
But it doesn't feel like a proper solution in terms of coding correctness. Is there any alternative?
Thanks
Upvotes: 2
Views: 820
Reputation: 477338
Here's a C++ solution to turn a pointer-to-object into a pointer-to-const-object:
#include <type_traits>
template <typename T>
using more_const_ptr = typename std::enable_if<
std::is_pointer<T>::value,
typename std::add_pointer<
typename std::add_const<
typename std::remove_pointer<T>::type>::type>::type>::type;
Usage:
using p = int *; // or "typedef int * p;" in C++03
int a = 10;
more_const_ptr<p> q = &a;
// *q = 20; // Error, q is "const int *"
(In C++14 there are useful shortcuts that make this more readable:)
template <typename T>
using more_const_ptr = std::enable_if_t<
std::is_pointer<T>::value,
std::add_pointer_t<std::add_const_t<std::remove_pointer_t<T>>>>;
Upvotes: 4
Reputation: 103733
#include <type_traits>
...
typedef std::remove_pointer<ptr_t>::type base_type;
typedef base_type const* const_ptr_t;
If ptr_t
is actually a template parameter, rather than a concrete type, then you will need to throw a typename
in there:
typedef typename std::remove_pointer<ptr_t>::type base_type;
Upvotes: 3
Reputation: 214265
In line 1, as you say you have a pointer type and then make it const. This means you have a constant pointer to (non-constant) data. Declaring it as type const
won't solve anything, because C specifies that such a declaration is equivalent to const type
.
There is no work-around. Generally, it is a bad idea to hide a pointer underneath a typedef. This makes the code very hard to read, even if you have a coding standard for variable naming. Just look at the Windows API for a perfect example of how to turn the C language into something less readable.
So the quick & dirty solution is to keep digging your hole deeper by declaring a typedef const void* cptr_t;
. Or indeed use a macro, it is an equally bad solution.
The good solution is to forget all about hiding pointers behind typedefs and other such attempts to change the well-known C or C++ language into some mysterious, personal macro language.
Upvotes: 3