const pointer to const data and c++ lists - c++

I want to insert some elements to the list.
What I really want to do is to use "insert3" because it guarantee that the pointer won't change, and the data won't change.
But "insert2" and "insert3" give the following error, which "insert1" doesn't:
class A
{
public:
std::list<int*> l;
void insert(int* const a)
{
l.push_back(a); //works
}
void insert2(const int* a)
{
l.push_back(a);
/*
no instance of overloaded function "std::list<_Ty, _Ax>::push_back [with _Ty=int *, _Ax=std::allocator<int *>]"
matches the argument list
*/
}
void insert3(const int* const a)
{
l.push_back(a);
}
};
Thanks for your help!

Short answer
You should use a list<int const* const> as the type of l instead and then you can use any of your inserts including insert3.
Long answer
By inserting into a list<int*> you attempt to convert your int const* (pointer to const int) to an int* (pointer to int).
Since you are removing the guarantee that you will not edit the target of the pointer, this is not implicitly doable. You may use a const_cast (or c-cast) if you really wish to do this, but usually casting away const-ness is a very bad idea (tm).
Why making the pointer itself const won't change a thing
If you use version 3 using an int const* const (const pointer to const int), you are not getting anything more or less than the guarantee that the variable a will not be changed while insert3 is running. By inserting the pointer into your list, you are actually copying it. This means that no matter whether a is const or not, your resulting list item will be the type you specified in the beginning.
By making the list into list<int const* const> you ensure that any pointer inserted cannot be changed later on, and the value pointed to it can only be changed after explicitly getting rid of the constness of your pointer. Inserting into it is possible, since adding const is always implicitly possible

Change the list to take a pointer to const:
std::list<const int*> l;
Since you had a pointer to const for the parameter, taking away its const-ness through an implicit conversion wouldn't be allowed.

It is one of the typical higher-level "issues" with C++-style compile-time const-correctness type system.
If you want to store int * pointers in your list, then you will not be able to add const int * pointers to that list (for obvious reasons). This will allso force all your insert methods to accept int * pointers, not const int * pointers.
I understand, that what you really want to express is that insert method itself does not change the pointed data (and it doesn't). However, as you can see, insert has some far-reaching side-effects - it stores the pointer in a list. This would potentially violate the const-correctenss if insert accepted const int * pointers.
In other words, it is not enough to consider what insert is doing by itself, it is also important to consider what possibilities insert opens to other code (in this case - to other code that has access to the same list). And in your case the possibilities it opens would easily allow const-correcness violations in other code if your insert quietly accepted const int * pointers.
You can, of course, impose your own vision of proper const-correctness in this case by using forceful const_casts. But it won't look pretty.

Related

Function scope regarding pointers in C++ (or C)

I am attempting to write portable code that allows the function to access a variable like an array, even if it is just a single value. The idea behind it is that the code will not make an array of size 1, but I need to be able to loop over all the values in the array if it is an array. Since I can't use sizeof(foo) to determine whether the memory is larger than a single instance sizeof(foo)/sizeof(int) might work, but it is too cumbersome to include in the main code. Macros wouldn't help because if I used a ternary operator like I'd expect #define ARRAY_OR_NOT(foo, type) (sizeof(foo)/sizeof(type) > 1) ? (foo) : (&foo) to return a pointer, in order to access with indexing. This problem is the compiler doesn't like the mixing of types between pointers and non-pointers.
So my second attempt was function overloading.
int * convert(int value)
{return &value;}
int * convert(int * value)
{return value;}
I know that this wouldn't work, because the first function would return the address of the temporary variable copy in that function scope. So my third attempt was
int * convert(int * value)
{return value;}
int * convert(int ** value)
{return *value;}
Every time I would call convert, pass the address of the value: convert(&foo).
This should work, and (I think) it avoids returning a temporary function scope
address. The result of convert would be accessible with indexing. In a controlled for loop, the code would run smoothly. The program would know how many elements are in value, but it would be faster to run everything inside a for loop than not.
So why does my second block of code produce the "Warning returning temporary scope blahblahblah" warning?
UPDATE: Major XY problem here.
Basically I'm trying to wrap all my code in a loop and access each value in a variable, one value per loop iteration. The system would know how many values are in that variable, but the code base is so large that wrapping everything in an if/else would be slow. So the way to access some value in the for loop with an index would be int foo = convert(&maybeArray)[counter]; Then I would use foo several times in the for loop.
For some reason Visual Studio was throwing an error while with the second block of code. Added this to OP.
Another solution would be to make 2 functions with overloaded operators that would basically execute the entire code, without converting each variable, but the code base is very large, and this needs to be as portable as possible. Referencing convert would be more future proof I would believe.
You've tagged this as C++, so I'm assuming you are using a C++ compiler.
There's a lot going on in your question, so I'm going to simplify. You want a C++ function convert(x) that will:
if x is an array, return the address of the first element
if x is not an array, return &x.
(Generally, maybe you need to redesign this whole thing, convert seems like a pretty strange function to want).
template<typename T, size_t N>
auto convert( T (&t) [N] ) -> T* {
return t; // just let pointer decay work for us here
}
template<typename T>
auto convert( T &t) -> T* {
return &t;
}
And, in C++, I would never use sizeof with things that I think are arrays. This template technique is a safer way to count the number of elements in an array.
Also, do you expect to have arrays of pointers, and to want to treat a single pointer as a single-element-array of pointers? If so, then tread carefully. Something that looks like an array, might actually be a pointer, e.g. arrays in parameter lists foo(int is_really_a_pointer[5]) { ...}. See the comment by #MSalters for more. Might be good to use his assert to catch any surprises. If you're just using int, then don't use the typename T in my templates, just force it to be int for clarity.
Finally, maybe instead of turning arrays into pointers, you should ask for a function that turns a non-array into a reference to a single-element array?
Update Here is a more complete example showing how to use convert and convert_end to find the beginning and end of an array to iterate over all the elements in an array; where, of course, a non-array is treated as an array of one element.
In C, there exist only pass by value. When you pass a pointer to a function then its address is copied to the function parameter. This simply means that if p is a pointer in calling function then a function call
int x = 5;
int *p = &x;
int a = foo(p);
for function definition
int foo(int *p1)
{
return *p1*2;
}
is implies that:
copy the address p points to parameter p1, i.e make p and p1 points to the same location.
any changes to the location pointed by p1 in function foo is reflected to *p because p and p1 is pointing to same location. But, if at any point p1 points to another location then this does not imply that p will point to that location too. p and p1 are two different pointers.
When you you pass a pointer to pointer, as in your last snippet of second block,
int * convert(int ** value)
{return *value;}
if *value changes to points to different location after argument is passed to it, then that pointer whose address is passed will also be updated with this location. In this case no need to return *value, but returning do no harm.

Applying const_cast on this-> pointer

I was playing with some code to remove constant-ness of variable.
int *i = new int(202);
int *j = new int(402);
int *const iptr = i; // Constant pointer
//iptr = j ; // Not allowed. Constant pointer cannot point to another location.
(*iptr)++; // Allowed
const_cast<int *>(iptr) = j;
cout<< *iptr // prints 402
It works as expected but when I try to remove constantness of "this" pointer, Compiler doesnt allow it, i.e. it shows squiggling lines underneath the const_cast statement.
class A
{
public:
A(A * obj)
{
const_cast<A *>(this) = obj;
}
};
When I hovered mouse (I am using VS2014) over "this" and "iptr" from earlier code, I could see the type is same i.e. <classname> *const
Can anybody please explain what is going on under the hood?
Cheers,
Saket
I am afraid you did not understand what const_cast is for.
In C++, const is used in two instances:
a const object logical value cannot be changed (and, barring mutable fields, its bitwise value cannot be changed either)
const* or const& are read-only pointers or references
const_cast is not about changing const objects, it's about modifying non-const objects through read-only pointers or references
Bear in mind though that shooting yourself in the foot is easy, because when you get a const& how do you know whether the original object is const or not ? You do not. And if you attempt to change one that is const, a unicorn appears, or maybe the devil (also know as Undefined Behavior: anything may happen).
Now, the correlation with this is tricky. Strictly speaking this is an r-value (meaning it can only appear as-is on the R ight-hand side of =), though it is often described as simply being const for simplicity's sake, so in a constructor of A this is described as having type A* const. Thankfully for us, even in this approximation const_cast is a bad idea since the original object is const.
Therefore, the recommendation is:
Junior: Do not use const_cast, reinterpret_cast or C-style casts (because it is not obvious when they desugar to one of the first two).
Senior: You are not experienced enough.
Expert: Come on! How can you claim you are an expert and attempt to use them ?
this is not an l-value.
You cannot assign it to point to something else.
You can do *this = *obj; which does not require a const_cast
You can do a const_cast<A*>(this) to override constness, and as with any other const_cast is fraught with danger, but it would enable you to perform a const/non-const overload without having to duplicate the implementation e.g.
T& A::get()
{
// some complex code to find the right reference, assigning to t
return t;
}
const T& A::get() const
{
// implement in terms of above function
return (const_cast<A*>(this))->get(); // invokes above
// and automatically converts the reference to const
}

How to pass const pointer in parameter non-const

I have two pointers (const Vec* a and const Vec b)
in a given piece of code, I need to pass these two values​​, which are instantiated during the code, for a function that has no parameter (const Vec *) but only (Vec *).
How could I do this without moving the function definition, but if necessary, what procedure should I take?
//const Vec* from;
//const Vec* at;
Vec* viewVec;
viewVec = Vec::sub( view->at, view->from);
//static Vec* sub(Vec*, Vec*);
Vec* Vec::sub(Vec* a, Vec* b) {
return new Vec(a->x - b->x, a->y - b->y, a->z - b->z);
}
The simplest answer is probably: "don't". If you need to use a Vec * instead of a Vec const *, then declare it that way to begin with.
If this is some third party function that promises not to modify it but for some reason has an aversion to const, then the const_cast solutions that other people listed is your only choice (other than to use a better third-party library).
If the std::vector that the pointer you have points to is actually not const (at its point of declaration), and you just happen to have a std::vector const * that refers to it, then it's 'safe' (but still generally unwise) to use const_cast on it. However, if you modify any variable that was originally declared as being const, then it is undefined behavior. For instance, the compiler may see that you are doing some expensive operation on a std::vector const multiple times, and it's free to cache certain parts of the result because it can assume that it's always dealing with the same thing, so if you change it, you may get incorrect (or even inconsistent) results.
You can use const_cast for this, e.g.
viewVec = Vec::sub(const_cast<Vec*>(view->at), const_cast<Vec*>(view->from));
Whether or not you should is another matter. If you really can't change the signature of the function (which is probably the easiest fix), you can always write a wrapper which contains the dodgy casting - that way, at least the caller doesn't need to do any casting itself:
Vec *Vec::sub(const Vec *a, const Vec *b) {
return sub(const_cast<Vec*>(view->at), const_cast<Vec*>(view->from));
}
const_cast<type>(value) There ya go ;)
As people have mentioned you could use const_cast. The reason you have to be careful doing this is that you might end up modifying something that shouldn't be modified. For exampl, if some object declares a pointer as const it is because it wants to ensure that this pointer cannot change. If you then const_cast the pointer and pass it to another function, the other function could make it point at something new, hence screwing with the original object which tried to protect it.
In particular, what if object A allocated some piece of memory which the const pointer points to. If you then pass the pointer to a function via const_cast and this function deletes the memory, or re-allocs it, then the original piece of memory will exist undeleted.
Hope this helps.

How are function pointers type unsafe

First of all type-safe means that anything that a compiler can catch straight away if done incorrectly.
Now, I heard function pointers are not type safe however whenever I tried to use them incorrectly the compiler did report errors for me. So, how is it type unsafe ?
E.g This is a function prototype that takes in a function pointer
void SortElements(void* MyArray, unsigned int iNumofElems,size_t size, int(*compare_funct)(void* First,void* SecondElem))
I have defined few functions to pass to it as:
int MySortAsc(void* First, void* Second);
void MyFunct2();
void MyFunct3(void* First);
The code only compiles for:
SortElements(MyArray, 10, sizeof(DataType), &MySortAsc); //Compiles
SortElements(MyArray, 10, sizeof(DataType), &MyFunct2); //Fails
Any idea how can I mis-use function pointers here ?
Is it because of this:
void (*functionPointer)();
...
int integer = 0xFFFFFFFF;
functionPointer = (void(*)())integer;
functionPointer();
Answer:
What I got to see is that function pointers in C++ are type safe. Ofcourse, they can be used in an unsafe manner by casting it incorectly but that does not make them a reason to be called as type unsafe. .NET delegates are strongly typed as well and to me it looks like both are type safe.
So, how is it type unsafe ?
void SortElements(void* MyArray, // what type is pointed here?
unsigned int N, // Are there really N elements?
size_t size, // Is the size correct?
int(*cmp)(void*,void*)); // Is this the correct function?
The code that you present is type-unsafe, not because of the function pointer but rather because of the use of void* in both the SortElements signature and the signature of the function pointer.
The reason why this is unsafe is because the caller has the whole responsibility of passing the right arguments, and the compiler cannot ensure that the pointer MyArray points to a contiguous memory region that holds iNumofElems each of which has the size offered in the interface. If the programmer makes a mistake, the compiler will not be able to help there, if a maintainer modifies the type stored in the array (size changes) or the number of elements, the compiler will not be able to detect it and tell you that you need to update the call to SortElements. Finally, because the function pointer that is passed also uses void*, the signature of a comparator that compares apples and pears is exactly the same, and the compiler cannot help if you pass the incorrect function pointer.
struct Apple {
int weight;
};
struct Pear {
double weight;
};
int compare_pears( void * pear1, void * pear2 ) {
return static_cast<Pear*>(pear1)->weight - static_cast<Pear*>(pear2)->weight;
}
int main() {
Apple apples[10];
SortElements( apples, 20, sizeof(Pear), compare_pears );
}
While the compiler is able to verify that the signature of the function pointer matches the signature that the function needs, the function pointer itself is unsafe, and allows you to pass a comparator for basically anything.
Compare that with this other alternative:
template <typename T, std::size_t N>
void SortElements( T (&array)[N], int (*cmp)( T const &, T const & ) );
Here the compiler will infer the type of the elements T and the size of the array N from the call. There is no need to pass the size of T, as the compiler knows it. The comparator function passed to this version of SortElements is strongly typed: it takes two constant references to the type of the element stored in the array and returns an int. If we tried this in the previous program:
int compare_pears( Pear const & lhs, Pear const & rhs );
int compare_apples( Apple const & l, Apple const & r );
Apple array[10];
//SortElements( array, compare_pears ); // Error!!!!
SortElements( array, compare_apples ); // Good!
You cannot mistake the size of the array or the size of the elements, if someone changes the type Apple, the compiler will pick it up, if the size of the array changes, the compiler will pick it up. You cannot mistake the comparator that is passed to the function as the compiler will also pick it up. Now the program is type safe, even if it uses function pointers (that might have an impact in performance as they inhibit inlining, which is why std::sort is usually faster than qsort)
Function pointers are type safe. However, many environments force upon the programmer the need to recast them. An incorrect casting could cause significant problems.
Function pointers are in fact type checked and are type safe.
Function pointers are strongly discouraged in nesC (a dialect of C used in TinyOs), for the reason that they hinder optimisation. Here static code analysis (or rather the lack of its applicability) is a bigger concern than type-safety, but I'm not sure whether these issues could be confused.
Another issue might be the use of function pointers as event handlers. When using a general event scheduler, you may want to abstract from the proper type, which would mean that you could have the idea to store function pointers as void* just for the sake of modularity. This would be a prominent example of type-unsafe usage of function pointers instead of type-safe dynamic binding usage.

When to use const and const reference in function args?

When writing a C++ function which has args that are being passed to it, from my understanding const should always be used if you can guarantuee that the object will not be changed or a const pointer if the pointer won't be changed.
When else is this practice advised?
When would you use a const reference and what are the advantages over just passing it through a pointer for example?
What about this void MyObject::Somefunc(const std::string& mystring) What would be the point in having a const string if a string is in fact already an immutable object?
Asking whether to add const is the wrong question, unfortunately.
Compare non-const ref to passing a non-const pointer
void modifies(T &param);
void modifies(T *param);
This case is mostly about style: do you want the call to look like call(obj) or call(&obj)? However, there are two points where the difference matters. If you want to be able to pass null, you must use a pointer. And if you're overloading operators, you cannot use a pointer instead.
Compare const ref to by value
void doesnt_modify(T const &param);
void doesnt_modify(T param);
This is the interesting case. The rule of thumb is "cheap to copy" types are passed by value — these are generally small types (but not always) — while others are passed by const ref. However, if you need to make a copy within your function regardless, you should pass by value. (Yes, this exposes a bit of implementation detail. C'est le C++.)
Compare const pointer to non-modifying plus overload
void optional(T const *param=0);
// vs
void optional();
void optional(T const &param); // or optional(T param)
This is related to the non-modifying case above, except passing the parameter is optional. There's the least difference here between all three situations, so choose whichever makes your life easiest. Of course, the default value for the non-const pointer is up to you.
Const by value is an implementation detail
void f(T);
void f(T const);
These declarations are actually the exact same function! When passing by value, const is purely an implementation detail. Try it out:
void f(int);
void f(int const) {/*implements above function, not an overload*/}
typedef void C(int const);
typedef void NC(int);
NC *nc = &f; // nc is a function pointer
C *c = nc; // C and NC are identical types
The general rule is, use const whenever possible, and only omit it if necessary. const may enable the compiler to optimize and helps your peers understand how your code is intended to be used (and the compiler will catch possible misuse).
As for your example, strings are not immutable in C++. If you hand a non-const reference to a string to a function, the function may modify it. C++ does not have the concept of immutability built into the language, you can only emulate it using encapsulation and const (which will never be bullet-proof though).
After thinking #Eamons comment and reading some stuff, I agree that optimization is not the main reason for using const. The main reason is to have correct code.
The questions are based on some incorrect assumptions, so not really meaningful.
std::string does not model immutable string values. It models mutable values.
There is no such thing as a "const reference". There are references to const objects. The distinction is subtle but important.
Top-level const for a function argument is only meaningful for a function implementation, not for a pure declaration (where it's disregarded by the compiler). It doesn't tell the caller anything. It's only a restriction on the implementation. E.g. int const is pretty much meaningless as argument type in a pure declaration of a function. However, the const in std::string const& is not top level.
Passing by reference to const avoids inefficient copying of data. In general, for an argument passing data into a function, you pass small items (such as an int) by value, and potentially larger items by reference to const. In the machine code the reference to const may be optimized away or it may be implemented as a pointer. E.g., in 32-bit Windows an int is 4 bytes and a pointer is 4 bytes. So argument type int const& would not reduce data copying but could, with a simple-minded compiler, introduce an extra indirection, which means a slight inefficiency -- hence the small/large distinction.
Cheers & hth.,
The main advantage of const reference over const pointer is following: its clear that the parameter is required and cannot be NULL.
Vice versa, if i see a const pointer, i immedeately assume the reason for it not being a reference is that the parameter could be NULL.