Const to Non-Const Conversion in C++

const to Non-const Conversion in C++

You can assign a const object to a non-const object just fine. Because you're copying and thus creating a new object, constness is not violated.

Like so:

int main() {
const int a = 3;
int b = a;
}

It's different if you want to obtain a pointer or reference to the original, const object:

int main() {
const int a = 3;
int& b = a; // or int* b = &a;
}

// error: invalid initialization of reference of type 'int&' from
// expression of type 'const int'

You can use const_cast to hack around the type safety if you really must, but recall that you're doing exactly that: getting rid of the type safety. It's still undefined to modify a through b in the below example:

int main() {
const int a = 3;
int& b = const_cast<int&>(a);

b = 3;
}

Although it compiles without errors, anything can happen including opening a black hole or transferring all your hard-earned savings into my bank account.

If you have arrived at what you think is a requirement to do this, I'd urgently revisit your design because something is very wrong with it.

Assignment of const to non-const in C

If you never want to modify A through its pointer from adt, then you should make that pointer const as well, i.e.:

struct adt {
const void * A;
};

That will make the error go away.

If you do want to modify A through adt, then new_adt should take a non-const pointer.


Edit: A more general note, which may help:

The const keyword, in general, applies to the type immediately to its left. However, if there is no type to its left, it will apply to the type to the right. So:
const int * A is the same as int const * A (the const applies to the int, not to the pointer), but in int * const A, the const applies to the pointer, not to the int.

There is a more comprehensive explanation on Wikipedia: const-correctness. The 'Pointers and References' section of that page includes an example which covers the various combinations of const and non-const that you can apply to a pointer.

Casting Const to non Const in c

This hack will do it. In practice sizeof(void *) is equal to sizeof(size_t) on every but the most obscure platforms. Nevertheless, I'd advise against using this. You should drop -Weverything instead. Standard C functions date back as far as 70', and the initial C compilers were much less strict than today's Clang or GCC with all of the warnings enabled. The fact that you'll find something "unsafe" in some of them is unavoidable.

void * memchr_(const void * ptr_, int c, size_t num);

int main(void)
{
unsigned char ary[] = { 1, 6, 2, 45, 23, 75, 23, 43, 23 },
* ptr = NULL;

ptr = memchr_(ary, 23, sizeof(ary) / sizeof(ary[0]));
printf("ary = %p, ptr = %p, *ptr = %u\n", (void *)ary, (void *)ptr, *ptr);
return 0;
}

void * memchr_(const void * ptr_, int c, size_t num)
{
size_t i;
const unsigned char * ptr = ptr_;

for(i = 0; i < num; i++) {
if(ptr[i] == (unsigned char)c) {
/* Casting to size_t first so that the compiler doesn't complain */
return (unsigned char *)(size_t)ptr + i;
}
}
return NULL;
}

Casting const pointer to non const

Does this mean that the elements of the array can now be changed?

It means that the type of the pointer is such that it is well-formed to modify the object through the pointer. This means that the compiler is not required to give you a diagnostic message and assuming the entire program is well-formed, the compiler is required to not fail compilation (some restrictions apply).

However, if the pointed object is a const object then the behaviour of modifying it through the pointer to non-const would be undefind.

But the vector elements in this case are non-const (because the template type argument is non-const), so modifying them would be defined. It might be surprising to the reader of the program though. Another matter is whether std::istringstream ever modifies the pointed objects or not.

casting non const to const in c++

const_cast can be used in order remove or add constness to an object. This can be useful when you want to call a specific overload.

Contrived example:

class foo {
int i;
public:
foo(int i) : i(i) { }

int bar() const {
return i;
}

int bar() { // not const
i++;
return const_cast<const foo*>(this)->bar();
}
};

Why is implicit conversion from const to non-const allowed?

A standards compliant compiler would "see" the for loop as follows:

auto&& __range = m; 
for (auto __begin = std::begin(m), __end = std::end(m); __begin != __end; ++__begin) {
const std::pair<std::string, int>& p = *__begin;
//loop_statement
}

Which basically boils down your question to why the following code is allowed:

std::pair<std::string, int> p = std::pair<const std::string, int>{};

Note that I dropped the const& part of p, because it isn't relevant. The conversion is the same, the only difference is that the temporary is bound to a reference instead of being copied.

If you're wondering why OP's snippet doesn't work with a non-const reference, the conversion is the reason why. The result of the conversion is a temporary object, and because any change to the temporary will be useless (its lifetime isn't extended and so it is destroyed right after), so the language disallows it.

This is allowed because std::pair has a constructor that enables this conversion.

template< class U1, class U2 >
pair( const pair<U1, U2>& p );

In your case, U1 is deduced as const std::string and U2 as int. It doesn't actually matter what cv qualifiers U1 and U2 have, because p's elements get copied.

The benefits are the same as to why this is allowed:

const int zero{};
int zero2 = zero;

For example, consider the following non-realistic example:

struct {
std::pair<int, int> pos;
} player;

std::pair<const int, const int> treasure{1, 2}; // position of treasure
player.pos = treasure; // ok

Now what if, as you say, this conversion were for some reason not allowed. What would the programmer have to do?

player.pos.first = treasure.first;
player.pos.second = treasure.second;

If this would also be disallowed, then the case with the zeroes above would also not be allowed, which doesn't really make sense, because you are copying zero, so it shouldn't matter if you can modify it or not, because that is a totally different operation.

If this is allowed, then why would player.pos = treasure; be disallowed, because the only thing that it does is copying? Like above, it shouldn't matter whether you can change the elements of treasure, because you are only copying them.

This is also why you should use auto&& or const auto& for ranged loops (and maybe even in general?) because it can avoid a copy if you're not careful.

Copy pointer to const to pointer to non const via memcpy

The initialization void *b = a; isn't valid C, it violates the rule of simple assignment C17 6.5.16.1 (initialization follows the rules of assignment), which states that in order for the expression to be valid:

...the type pointed to by the left has all the qualifiers of the type pointed to by the right.

You might want to compile with -pedantic-errors to get errors instead of warnings for C language violations.


As for well-defined behavior - just as long as you de-reference the pointer using the correct type of the actual data, it is well-defined behavior, and the type of the pointer itself doesn't matter much.

I don't even understand why you need to convert to void*, since the format of your callback is this:

int (*comp)(const void *, const void *)

So the only problem is the return type of the outer function, which could be simplified to something like this:

void* vector_lsearch (const void* key, const void* base, int (*comp)(const void*, const void*))
{
const struct vector* vector = CONST_VECTOR(base);
void* result = NULL;
unsigned char* data = (unsigned char*)base;

for (size_t i=0; i < vector->size; i++)
{
if (comp(&data[i*vector->szof], key) == 0)
{
result = data;
break;
}
}
return result;
}

CONST_VECTOR is fishy though, smells like you are hiding a cast behind a macro or something?



Related Topics



Leave a reply



Submit