Question about exact time of destruction of temporaries in C++ - c++

is the following code safe (it works in DEBUG) :
void takesPointer(const Type* v);//this function does read from v, it doesn't alter v in any way
Type getValue();
...
takesPointer(&getValue());//gives warning while compiling "not an lvalue"
...
Type tmp = getValue();
takesPointer(&tmp);//this is safe, and maybe I should just do it, instead of posting here
so - is it safe ? should I just forget about it and use the code with the explicit tmp ?
but anyways - I'm still interested if the optimizer is allowed to kill the temporary before returning from this call :
takePointer(&getValue())
EDIT:
thank you all !
unfortunately I can't change the function "takesPointer" (it's part of a library), I could only wrap it in a function "takesReference", which calls takesPointer - would this eliminate the copy, or would the compiler still be allowed to create a copy (the "Type" is a int-3x3-Matrix, so it wouldn't be THAT bad, but still...) ?
inline void takesReference(const Type& v){ takesPointer(&v); }
About the time of destruction : will it be destroyed after "takesPointer" RETURNS, or after it's CALLED ?

As other answers have stated you cannot take the address of a temporary. However, if you change the signature of
void takesPointer(const Type* v);
to
void takesPointer(const Type& v);
then the following code should compile without warnings:
takesPointer(getValue());
because you are allowed to bind a temporary to a const reference, and it should work just the same.

The Standard forbids you to do &getValue() - exactly because it's not an lvalue. Ordinarily, if this was allowed, then the temporary resulting from that function call will live until the outer function returns and every other thing in the whole expression has completed being processed. This can be called "destroying temporaries after end of full-expression", and ensures things like the following works as expected
// the temporary string is alive until the whole expression has been processed
cout << string("hello");
The compiler gives you a diagnostic - that's all the Standard requires for ill-formed code. It doesn't force the compiler to abort compilation, for instance. But after code being ill-formed was diagnosed, the compiler can do everything it wants. So if you want to know what the compiler does in your case, you should read its manual.

This will prevent copies* and compiles.
const Type& tmp = getValue();
takesPointer(&tmp);
Prevent copies is a bit strong because the compiler will often do this for you.
You have to have access to the copy constructor but the compiler will often not use it:
#include "iostream"
class Type
{
public:
explicit Type(int val) : m_val(val) { std::cout << "ctor";};
Type(const Type& copy)
{
std::cout << "copy";
};
private:
int m_val;
};
Type getValue() { Type r(0); return r;};
void takesPointer(const Type* const)
{
};
int main(int argc, char* argv[])
{
const Type tmp = getValue();
takesPointer(&tmp);
}
Will print only "ctor" in release and "ctorcopy" in debug. (MVS2005)

You are allowed to bind a non-const rvalue to a const reference lvalue, but you're binding it to a const pointer lvalue.
And no, the optimzier can't destruct the result of getValue() before calling takePointer().

Yes, it is safe, albeit illegal in the current form. You can work around the error by using an explicit intermediate cast to const-reference type
takesPointer( &(const Type &) getValue() );
This makes it perfectly legal as long as the temporary object is alive, which is till the end of evaluation of the full expression.
Moreover, you can even cast away the constness and modify the temporary object through the pointer (keeping in mind that it will be destroyed at the end of full expression). This is perfectly legal as long as the temporary object itself is not constant.
Using a comma operator, you can "stretch" full expressions, and thus write quite extensive sequences of operations that work with a "long-lived" temporary object
Type *p;
p = &(Type &) (const Type &) getValue(), modify(p), print(p), modifyAgain(p), print(p);
// Not using C++ casts for brevity
The practice is rather questionable though and most of the time there's no point in doing this.

Related

Reference from literal

I am calling a function with the signature
void setValue(int& data)
I would like to pass a literal number to it:
setValue(1);
But I get:
error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
Is there a way I can make this work without changing the function (it's in a library) and without assigning each literal value to a variable?
Assuming setValue does not actually modify its argument and just has a wrong signature which you cannot change, here is an approach which is not thread-safe among other things:
#include <iostream>
void setValue(int &i)
{
std::cout << "i = " << i << std::endl;
}
int& evil(int i)
{
static int j;
j = i;
return j;
}
int main()
{
setValue(evil(1));
setValue(evil(2));
}
When you declare the argument as being an int&, you are saying that the function called can change the value and the caller will see the change.
So it is no longer valid to pass a literal value then because how could the function possibly change the given value of a literal?
If you don't want the setValue to be able to change the given value, make the argument either be an int or const int&. And if you do want the setValue function to be able to change the value, then the caller must declare a non-const variable to hold the int and pass in that.
Can I change something at the call site to make it work
The problem with your code is that you declared your function to expect a reference, which means the compiler has to prepare the code to allow the function to change whatever you pass into it at the call site. So yes, sure, you can declare a variable, set it to 1 and call your function with it.
Contrast this with a constant reference in the declaration, where the compiler knows you won't change it inside the function, and then you can pass a literal in without issues. In fact, any logical, thought out design will make setters accept constant parameters because it won't change them, it will just store a possibly processed value in its state.
The answer to „what do I do if a library has a bad interface and I can't change it“ is usually „write a wrapper“. Assuming this is a method of some class BadLibraryClass, you could do something like:
class Wrapper {
public:
BadLibraryClass inner;
setValue(int i) {
inner.setValue(i); // i is an lvalue
}
};
This is just a crude example. Perhaps inner is better off being a pointer, a reference or even a smart pointer. Perhaps you want a conversion operator to BadLibraryClass. Perhaps you can use inheritance to expose other methods of BadLibraryClass.
Two options:
Use the result of assignment:
static int _data;
void myCall() {
setValue((_data = 3));
}
Write a wrapper:
struct setValueW {
int _data;
// constructor
setValueW(int _data) : _data(_data) {
setValue(_data);
}
// if you want to call it again
void operator()() {
setValue(_data);
}
};
void myCall2() {
setValueW(3);
}
AFAIK, references keeps the addresses of the variable. 1 is not variable. It is temporary.
Take a look this article(this is a quote from this site)
c++11 introduced a new kind of reference variable -- an r-value reference
To declare one, use && after a type
int & // type designation for an L-value reference
int && // type designation for an R-value reference
L-value references can only refer to L-values
R-value references can reference to R-values (temporaries)
int x, y, z; // regular variables
int & r = x; // L-value reference to the variable x
int & r2 = x + y; // This would be ILLEGAL, since x + y is an R-value
int && r3 = x + y; // LEGAL. R-value reference, referring to R-value
So you can use (But this is not useful. It may be more useful if you write this in plain without rvalue or lvalue.):
void setValue(int&& data)
setValue(1);
Or you can use that:
void setValue(int& data)
int a = 11;
setValue(a);
Don't forget for second example. If you change the value of data parameter. You will have change the a variable value.
No, you can't.
An lvalue reference like that binds to a variable (roughly speaking).
Your literal is not such a thing. It never had a name, and may not even have a home in memory.
Your two options are the two things you ruled out, I'm afraid.
For what it's worth, this is not your fault: that is a rather poor setter. It should take const int& (which will automatically create a nice temporary variable for you out of the literal!), or even just const int.

Why is conversion from const pointer-to-const to const pointer-to-nonconst in an initializer list allowed

I read the question posted on
Why does C++ not have a const constructor?
I am still confused why that program can compile. And I tried to offer my opinion on the question, I don't know why it was deleted. So I have to ask the question again.
Here is the program
class Cheater
{
public:
Cheater(int avalue) :
value(avalue),
cheaterPtr(this) //conceptually odd legality in const Cheater ctor
{}
Cheater& getCheaterPtr() const {return *cheaterPtr;}
int value;
private:
Cheater * cheaterPtr;
};
int main()
{
const Cheater cheater(7); //Initialize the value to 7
// cheater.value = 4; //good, illegal
cheater.getCheaterPtr().value = 4; //oops, legal
return 0;
}
And my confusion is :
const Cheater cheater(7)
creates a const object cheater, in its constructor
Cheater(int avalue) :
value(avalue),
cheaterPtr(this) //conceptually odd legality in const Cheater ctor
{}
'this' pointer was used to initialize cheaterPtr.
I think it shouldn't be right. cheater is a const object, whose this pointer should be something like: const Cheater* const this; which means the pointer it self and the object the pointer points to should both const, we can neither change the value of the pointer or modify the object the pointer points to.
but object cheater's cheaterPtr member is something like Cheater* const cheaterPtr. Which means the pointer is const but the object it points to can be nonconst.
As we know, pointer-to-const to pointer-to-nonconst conversion is not allowed:
int i = 0;
const int* ptrToConst = &i;
int * const constPtr = ptrToConst; // illegal. invalid conversion from 'const int*' to 'int*'
How can conversion from pointer-to-const to pointer-to-nonconst be allowed in the initializer list? What really happened?
And here is a discription about "constness" in constructors I tried to offer to the original post:
"Unlike other member functions, constructors may not be declared as const. When we create a const object of a class type, the object does not assume its 'constness' until after the constructor completes the object's initialization. Thus, constructors can write to const objects during their construction."
--C++ Primer (5th Edition) P262 7.1.4 Constructors
If constructors were const, they couldn't construct their object - they couldn't write into its data!
The code you cite as "legal:"
cheater.getCheaterPtr().value = 4; //oops, legal
is not actually legal. While it compiles, its behaviour is undefined, because it modifies a const object through a non-const lvalue. It's exactly the same as this:
const int value = 0;
const int * p = &value;
*const_cast<int*>(p) = 4;
This will also compile, but it's still illegal (has UB).
Your assumptions are incorrect. Taking them one at a time, first code annotation.
class Cheater
{
public:
Cheater(int avalue) :
value(avalue),
cheaterPtr(this) // NOTE: perfectly legal, as *this is non-const
// in the construction context.
{}
// NOTE: method is viable as const. it makes no modifications
// to any members, invokes no non-const member functions, and
// makes no attempt to pass *this as a non-const parameter. the
// code neither knows, nor cares whether `cheaterPtr`points to
// *this or not.
Cheater& getCheaterPtr() const {return *cheaterPtr;}
int value;
private:
Cheater * cheaterPtr; // NOTE: member pointer is non-const.
};
int main()
{
// NOTE: perfectly ok. we're creating a const Cheater object
// which means we cannot fire non-const members or pass it
// by reference or address as a non-const parameter to anything.
const Cheater cheater(7);
// NOTE: completely lega. Invoking a const-method on a const
// object. That it returns a non-const reference is irrelevant
// to the const-ness of the object and member function.
cheater.getCheaterPtr().value = 4;
return 0;
}
You said:
I think it shouldn't be right. cheater is a const object whose this pointer should be something like: const Cheater* const this
cheater is const after construction. It must be non-const during construction. Further, the constructor does not (and cannot) know the caller has indicated the object will be const. All it knows is its time to construct an object, so thats what it does. Furthermore, after construction &cheater is const Cheater *. Making the actual pointer var itself also const is simply non-applicable in this context.
And then...
...object cheater's cheaterPtr member is something like Cheater* const cheaterPtr;
This is actually an incredibly accurate way to describe this. Because cheater is const its members are as well, which means the cheaterPtr member is const; not what it points to. You cannot change the pointer value, but because it is not a pointer-to-const-object you can freely use that pointer to modify what it points to, which in this case happens to be this.
If you wanted both the pointer and its pointed-to-object to be const you whould have declared it as const Cheater *cheaterPtr; in the member list. (and doing that, btw, makes only that mutable action through the getCheaterPointer() invalid. It would have to return a const Cheater* as well, which means of course the assignment would fail.
In short, this code is entirely valid. What you're wanting to see (construction awareness of the callers const-ness) is not part of the language, and indeed it cannot be if you want your constructors to have the latitude to... well, construct.

Relevance of const return type in NRVO cases

This is a follow up question from Calling constructor in return statement.
This a operator overload fun in a class.
const Integer operator+(const Integer& IntObject)
{
cout << "Data : " << this->data << endl;
return Integer(this->data + IntObject.data);
}
What is the relevance of const in the return type for such functions?
int main()
{
Integer A(1); //Create 2 object of class Integer
Integer B(2);
const Integer C = A + B; //This will work
Integer D = A + B; //This will also work
fun(A + B); //Will work
}
void fun(Integer F) {}
This is a case temporaries are not created during return step due to NRVO. The object to be returned is directly constructed on the callee's address.
Here's a better example:
struct Foo
{
void gizmo();
Foo const operator+(Foo const & rhs);
};
Now if you have a Foo x; Foo y;, then you cannot say:
(x + y).gizmo(); // error!
The constant return value means you cannot use it for non-constant operations. For primitive types this is not quite so relevant, because there aren't many non-constant operations you can perform on temporary objects, because lots of "interesting" operations (like prefix-++) aren't allowed on temporaries.
That said, with C++11 one should really try and adopt the new idiom of never returning constant values, since non-constant values are now amenable to move optimisations.
Some people used to suggest doing that, to prevent writing nonsense like A + B = C. However, in C++11 it can prevent some optimisations since it makes the return value unmovable. Therefore, you shouldn't do it.
In this case, it also prevents you from writing perfectly valid code like D = A + B + C, but that's just because the author forgot to declare the operator const.
There is no relevance in your code snippet, because you are making a copy of the returned value.
In general, it is difficult to find good reasons to return a const value. I can only see it having an effect in this type of expression, attempting to call a non-const method on a const temporary:
(someObject.someMethodReturningConstValue()).someNonConstMethod(); // error, calls non const method on const temporary
so you should only use it if you want to disallow calling non-const methods on temporaries. On the other hand, it kills move-semantics in C++11 so is discouraged.

c++ overloading operators, assignment, deep-copy and addition

I'm doing some exploration of operator-overloading at the moment whilst re-reading some of my old University text-books and I think I'm mis-understanding something, so hopefully this will be some nice easy reputation for some answerers. If this is a duplicate please point me in the right direction.
I've created a simple counter class that has (at this stage) a single member, val (an int).
I have initialised three of these counters, varOne to varThree, and want the third counter to be the sum of the first two (e.g. varThree.val is set to 5 in the below code)
counter::counter(int initialVal)
{
val = initialVal;
//pVal = new int;
//*pVal = 10; // an arbitrary number for now
}
int main (int argc, char const* argv[])
{
counter varOne(3), varTwo(2), varThree;
varThree = varOne + varTwo;
return 0;
}
I've overloaded operator+ like so:
counter operator+(counter& lhs, counter& rhs)
{
counter temp(lhs.val + rhs.val);
return temp;
}
I've made this a non-member function, and a friend of the counter class so that it can access the private values.
My problem starts when adding another private member, pVal (a pointer to an int). Adding this means that I can no longer do a simple varThree = varOne copy because when varOne is destroyed, varThree.pVal will still be pointing to the same bit of memory.
I've overloaded operator= as follows.
int counter::getN()
{
return *newVal;
}
counter& counter::operator=(counter &rhs)
{
if (this == &rhs) return *this;
val = rhs.val;
delete pVal;
pVal = new int;
*pVal = rhs.getN();
return *this;
}
Now if I do something like varThree = varOne everything copies correctly, however trying to do varThree = varOne + varTwo gives me the following error:
counter.cpp: In function ‘int main(int, const char**)’:
counter.cpp:96: error: no match for ‘operator=’ in ‘varThree = operator+(counter&, counter&)(((counter&)(& varTwo)))’
counter.cpp:55: note: candidates are: counter& counter::operator=(counter&)
make: *** [counter] Error 1
It looks as though counter::operator= is having trouble coping with the return output from operator+, and that I need to overload operator= further to accept the type that operator+ is returning, but I've had no luck and I'm beginning to think that maybe I've done something fundamentally wrong.
You need to pass your parameters as const reference. For example:
counter& counter::operator=( const counter &rhs )
And similarly for operator+(). This is necessary in order to be able to bind temporary values to the function parameter(s). Temporary values are created when you return by value, so when you say:
varOne + varTwo
a nameless temporary is created. This is the right thing to do, but you have to make sure that functions such as the assignment op can accept such values by making their parameters const.
You also need to implement the copy constructor and destructor for your class, though lack of these will not cause compilation errors (unfortunately).
Another way to approach this problem is to use the PImpl pattern and swap for the assignment operator. Assuming that you still have a counter(int) constructor you could write operator= as follows
counter& counter::operator=(const counter& rhs) {
counter temp(rhs.getN());
std::swap(&pVal,rhs.pVal);
return *this;
}
This has the benefit of leaving the messy memory management functions in the constructor and destructor where they should be.
The key here (as touched upon by a previous poster) but worth emphasizing is that expressions in C++ can be categorized as being either rvalues or lvalues.
Their is much detail behind those categories, but a useful heuristic to guide your intuition is: if you can take the address of an expression (such as a variable) it is an lvalue (there is much more to the story here, but this is a good place to start).
If it is truly not an lvalue, it is an rvalue - and a useful heuristic for rvalues is that they represent "hidden" temporary objects that the compiler instantiates to make your code work. These objects are created and destroyed by the compiler behind the scenes.
Why is this relevant here?
Well, in C++98/03 (which is what i presume you are using), remember the following two rules:
1) Only lvalue expressions can bind to non-const references (ignoring casts)
2) rvalue expressions can bind to only const references (ignoring casts)
An example will help here:
// Consider the function foo below - it returns an int -
// whenever this function is called, the compiler has
// to behave as if a temporary int object with the value 5 is returned.
// The use of 'foo()' is an expression that is an rvalue - try typing &foo() -
// [Note: if foo was declared as int& foo(), the story gets complicated, so
// i'll leave that for another post if someone asks]
int foo() { return 5; }
void bind_r(int& r) { return; }
void bind_cr(const int& cr) { return; }
int main()
{
int i = 10; // ok
int& ri = i; // ok binding lvalue to non-const reference, see rule #1
int& ri2 = foo(); // Not ok, binding a temporary (rvalue) to a non-const reference
// The temporary int is created & destroyed by compiler here
const int& cri = foo(); // ok - see rule #2, temporary int is NOT destroyed here
//Similarly
bind_r(i); // ok - rule #1
bind_r(foo()); // NOT ok - rule #2
bind_cr(foo()); // ok - rule #2
// Since the rules above keep you out of trouble, but do not exhaust all possibilities
// know that the following is well-formed too:
const int& cri2 = i;
bind_cr(i);
bind_cr(cri);
bind_cr(cri2);
}
When you bind an rvalue to a const reference, you basically extend the temporary object's life-time to the life-time (in this case scope) of the reference (and the compiler can not just destroy it at the end of that expression) - so you end up with a reference to a valid object.
I hope this helps in understanding why you have to declare your assignment operator as accepting a const reference and not just a non-const reference, as one of the other posters rightly recommended.
p.s. There are some other issues with your code (such as why you are destroying and creating the memory that your object exclusively points to upon each assignment, and the lack of a copy constructor and destructor), and if no one has addressed them by the time this post appears, i will :)
p.s. It may also be worth knowing that C++0x adds something known as rvalue references (non-const) that preferentially bind to rvalues and provide for extremely powerful optimization opportunities for the programmer (without having to rely on the optimization capabilities of the compiler) - they also help solve the problem of creating the perfect forwarding function in C++ - but now we're digressing ;)

Is const_cast safe?

I can't find much information on const_cast. The only info I could find (on Stack Overflow) is:
The const_cast<>() is used to add/remove const(ness) (or volatile-ness) of a variable.
This makes me nervous. Could using a const_cast cause unexpected behavior? If so, what?
Alternatively, when is it okay to use const_cast?
const_cast is safe only if you're casting a variable that was originally non-const. For example, if you have a function that takes a parameter of a const char *, and you pass in a modifiable char *, it's safe to const_cast that parameter back to a char * and modify it. However, if the original variable was in fact const, then using const_cast will result in undefined behavior.
void func(const char *param, size_t sz, bool modify)
{
if(modify)
strncpy(const_cast<char *>(param), sz, "new string");
printf("param: %s\n", param);
}
...
char buffer[16];
const char *unmodifiable = "string constant";
func(buffer, sizeof(buffer), true); // OK
func(unmodifiable, strlen(unmodifiable), false); // OK
func(unmodifiable, strlen(unmodifiable), true); // UNDEFINED BEHAVIOR
I can think of two situations where const_cast is safe and useful (there may be other valid cases).
One is when you have a const instance, reference, or pointer, and you want to pass a pointer or reference to an API that is not const-correct, but that you're CERTAIN won't modify the object. You can const_cast the pointer and pass it to the API, trusting that it won't really change anything. For example:
void log(char* text); // Won't change text -- just const-incorrect
void my_func(const std::string& message)
{
log(const_cast<char*>(&message.c_str()));
}
The other is if you're using an older compiler that doesn't implement 'mutable', and you want to create a class that is logically const but not bitwise const. You can const_cast 'this' within a const method and modify members of your class.
class MyClass
{
char cached_data[10000]; // should be mutable
bool cache_dirty; // should also be mutable
public:
char getData(int index) const
{
if (cache_dirty)
{
MyClass* thisptr = const_cast<MyClass*>(this);
update_cache(thisptr->cached_data);
}
return cached_data[index];
}
};
I find it hard to believe that that's the only information you could find about const_cast. Quoting from the second Google hit:
If you cast away the constness of an
object that has been explicitly
declared as const, and attempt to
modify it, the results are undefined.
However, if you cast away the
constness of an object that has not
been explicitly declared as const, you
can modify it safely.
What Adam says. Another example where const_cast can be helpful:
struct sample {
T& getT() {
return const_cast<T&>(static_cast<const sample*>(this)->getT());
}
const T& getT() const {
/* possibly much code here */
return t;
}
T t;
};
We first add const to the type this points to, then we call the const version of getT, and then we remove const from the return type, which is valid since t must be non-const (otherwise, the non-const version of getT couldn't have been called). This can be very useful if you got a large function body and you want to avoid redundant code.
The short answer is no, it's not safe.
The long answer is that if you know enough to use it, then it should be safe.
When you're casting, what you are essentially saying is, "I know something the compiler doesn't know." In the case of const_cast, what you are saying is, "Even though this method takes in a non-const reference or pointer, I know that it won't change the parameter I pass it."
So if you do actually know what you are claiming to know in using the cast, then it's fine to use it.
You're destroying any chance at thread-safety, if you start modifying things that the compiler thought were const.