I have tried to solve an exercise from a book but I failed on the static_cast. I used the qsort Method from cstdlib. I have to cast the parameters of my function to a C-String (const char*). But I always get the error message: stattic_cast from type 'const void*' to type 'const char**' casts away qualifiers.
int scmp(const void *s1, const void *s2) {
const char *c1 = (static_cast<const char**>(s1));
const char *c2 = (static_cast<const char**>(s2));
....
}
const char *sfield[] = {"one", "two", "three", "four", "five"};
qsort(sfield, 10, 4, scmp);
The solution is as follows
const char *c1 = *(static_cast<const char* const*>(s1));
What is the reason for the last const and where does it come from? Why I have to cast to a pointer to a constant pointer to char const?
It comes from the origin pointer. static_cast may not discard the const qualifier. So you can only cast void const* to a T const*.
Now, it just so happens that your T is a char const*. You were probably led astray by the leading const in your original code. It does not apply where one may think it applied.
The qsort comparator parameters are pointers to const versions of the elements being compared. In your example the elements being compared are const char *, so a pointer to const of that is const char * const *. Hence the correct version of the code:
int scmp(const void *s1, const void *s2)
{
auto pc1 = static_cast<const char * const *>(s1);
auto pc2 = static_cast<const char * const *>(s2);
char const *c1 = *pc1;
char const *c2 = *pc2;
return strcmp(c1, c2); // or whatever
}
You can do away with pc1, pc2 and apply * operator to the result of the cast if you like .
Perhaps you mistakenly assumed the arguments were the elements being compared, when in fact they are pointers to the elements being compared .
If it is still not clear then maybe it would help to use a symbolic name for the element type:
using ELEMENT_T = const char *;
int scmp(void const *s1, void const *s2)
{
auto pc1 = static_cast<ELEMENT_T const *>(s1);
auto pc2 = static_cast<ELEMENT_T const *>(s2);
ELEMENT_T c1 = *pc1;
ELEMENT_T c2 = *pc2;
return strcmp(c1, c2); // or whatever
}
The same pattern would work for elements that are not pointers (e.g. integer elements).
Related
Is there any way I could write the two lines (7 and 8) of code into one line? I think I understand why the error occurs.
int value = 5;
int &GetValue() { return value; }
int main() {
const int *my_value = (const int *)&(GetValue()); // 7
const int *const *my_value_pp = (const int *const *)&(my_value); // 8
// This gives error for saying cannot take the address of an rvalue of type 'int *'
// const int* const * my_second_value_pp = (const int* const*)(&(&(Getvalue()));
}
I need this since there is a function (which I did not write) that takes a const int *const * as an argument.
First, the two lines does not require casting, so just write:
const int* my_value = &GetValue(); // 7
const int* const* my_value_pp = &my_value; // 8
You can however not write that as a one-liner as the function you are going to call needs the address of my_value. You can however skip my_value_pp and call your function using my_value directly:
void func(const int* const*) {} // example function taking a const int* const*
func(&my_value); // &my_value is a const int**
I've created a const array of const pointers like so:
const char* const sessionList[] = {
dataTable0,
dataTable1,
dataTable2,
dataTable3
};
What is the correct syntax for a regular non-const pointer to this array? I thought it would be const char**, but the compiler thinks otherwise.
If you actually need a pointer to an array, as your title suggests, then this is the syntax:
const char* const (*ptr)[4] = &sessionList;
const char* const sessionList[] = { ... };
is better written as:
char const* const sessionList[] = { ... };
Type of sessionList[0] is char const* const.
Hence, type of &sessionList[0] is char const* const*.
You can use:
char const* const* ptr = &sessionList[0];
or
char const* const* ptr = sessionList;
That declares a pointer to the elements of sessionList. If you want to declare a pointer to the entire array, it needs to be:
char const* const (*ptr)[4] = &sessionList;
The same type as you declared for the array elements, with an extra * added:
const char* const *
I am trying to implement memchr() function . my code must return a void * , so if we find the character we can change it . the problem is here . I have two approaches one approach is c_style .
void *memChr(const void *s1, int c, size_type n)
{
const char *p = (const char *)s1;
while (n--)
if (*p++== (char)c)
return (void *)--p;
return 0;
}
these approach uses c-style cast , here we send s1 as const , which is proper cause we don't want any change , and then we return p as a non const pointer to void which is again proper . any way this is old , and I want a more c++ approach. like this :
void *memChr( void *s1, int c, int n)
{
char *p = static_cast< char *>(s1);
while (n--)
if (*p++ == static_cast<char>(c))
return static_cast<void *>(p);
return 0;
}
my problem with these code is this : I cant cast a const pointer to a non const pointer .static_cast is safer than c style cast , but It makes me to use non const parameter which it is not appropriate . with standard memchr() parameters ,there is no way to be implemented with static_cast .
so which approach is better? I have just finished c++ tutorials , and I am trying to learn good coding , but I am a little confused .
You can use const_cast to cast from const to non-const pointer:
void *memChr( const char *s1, int c, int n)
{
char *p = const_cast< char *>(s1);
while (n--)
if (*p++ == static_cast<char>(c))
return static_cast<void *>(p);
return 0;
}
I have an issue, it doesn't want to cast using static_cast<>. What can it be?
void myCompare(const void *str)
{
const char *ca = *(static_cast<const char**>(str)); //error
const char *a = *(const char **)str; //ok
}
You're casting away const on the second level, which static_cast is not allowed to do (in fact, no "C++" cast apart from const_cast):
void const*
char const* *
// ^^^^^^^^^^^ ^^^^^
// pointee cv-qualifiers
// of pointee
Instead, write
const char *ca = *(static_cast<const char* const*>(str));
The (char const**) cast works here because it is equivalent to a static_cast followed by a const_cast (as per [expr.cast]/(4.3)) - i.e. it was equivalent to
const char *ca = *(const_cast<const char**>(static_cast<const char* const*>(str)));
What is best way to capture a smart pointer in a lambda? One attempt of mine lead to a use-after-free bug.
Example code:
#include <cstring>
#include <functional>
#include <memory>
#include <iostream>
std::function<const char *(const char *)> test(const char *input);
int main()
{
std::cout.sync_with_stdio(false);
std::function<const char *(const char *)> a = test("I love you");
const char *c;
while ((c = a(" "))){
std::cout << c << std::endl;
}
return 0;
}
std::function<const char *(const char *)> test(const char *input)
{
char* stored = strdup(input);
char *tmpstorage = nullptr;
std::shared_ptr<char> pointer = std::shared_ptr<char>(stored, free);
return [=](const char * delim) mutable -> const char *
{
const char *b = strtok_r(stored, delim, &tmpstorage);
stored = nullptr;
return b;
};
}
fails, as shown by AddressSanitizer.
A lambda (even one with a universal capture like [=]) only actually captures variables used within its definition. Since in your example, pointer is never used inside the lambda, it's not captured and thus when it goes out of scope, it's the last shared pointer referring to stored and free() is called.
If you want to capture pointer, you could force its use:
return [=](const char * delim) mutable -> const char *
{
pointer;
const char *b = strtok_r(stored, delim, &tmpstorage);
stored = nullptr;
return b;
};
However, this is rather hackish. You want your functor stateful and with nontrivial state management. To me, this is a strong indicator an actual named class (instead of a lambda) would be in order. So I would change it like this:
std::function<const char *(const char *)> test(const char *input)
{
struct Tokenizer
{
std::shared_ptr<char> pointer;
char* stored;
char* tmpstorage;
explicit Tokenizer(char* stored) : pointer(stored, free), stored(stored), tmpstorage(nullptr) {}
const char* operator() (const char * delim)
{
const char *b = strtok_r(stored, delim, &tmpstorage);
stored = nullptr;
return b;
}
};
return Tokenizer(strdup(input));
}
Just capture the variable by value and let the copy constructor and destructor worry about ownership semantics- that's what smart pointers are for.