I am using totalview as a linux C++ debugger. Functions in our code often look something like this
double foo() {
int a = 2;
int b = 3;
return bar(a,b);
}
where some preliminary work is done and than a more or less complex function bar is called a the return statement.
This is hard to debug with totalview, since the interesting return value can not be observed easily. Totalview can not evaluate the expressing bar(a,b). I can rewrite the code as
double foo() {
int a = 2;
int b = 3;
const auto retVal = bar(a,b);
return retVal;
}
Now, I can place a breakpoint at the return value and observe the in- and output of my function bar.
How can I do this without introducing a new (useless) variable?
Let the compiler optimise out the "useless" variable, by a process called named return value optimisation, and leave it in. (Personally though I would help the compiler as much as possible by using the return type of the function explicitly rather than auto; so there's no potential type conversion at the return stage.). For what it's worth, I do this all the time, even with heavy objects such as std::vector. You can always check the generated assembler if you suspect the compiler is making superfluous copies.
Then you can set a breakpoint at the appropriate place as you know.
In some debuggers you can inspect the function return value directly by peeking at a register, but this is by no means universal.
Reference: http://en.cppreference.com/w/cpp/language/copy_elision
Related
I've been using C/C++ for about three years and I can't believe I've never encountered this issue before!
This following code compiles (I've just tried using gcc):
#include <iostream>
int change_i(int i) {
int j = 8;
return j;
}
int main() {
int i = 10;
change_i(10);
std::cout << "i = " << i << std::endl;
}
And, the program prints i = 10, as you might expect.
My question is -- why does this compile? I would have expected an error, or at least a warning, saying there was a value returned which is unused.
Naively, I would consider this a similar case to when you accidentally forget the return call in a non-void function. I understand it's different and I can see why there's nothing inherently wrong with this code, but it seems dangerous. I've just spotted a similar error in some very old code of mine, representing a bug which goes back a long time. I obviously meant to do:
i = change_i(10);
But forgot, so it was never changed (I know this example is silly, the exact code is much more complicated). Any thoughts would be much appreciated!
It compiles because calling a function and ignoring the return result is very common. In fact, the last line of main does so too.
std::cout << "i = " << i << std::endl;
is actually short for:
(std::cout).operator<<("i =").operator<<(i).operator<<(std::endl);
... and you are not using the value returned from the final operator<<.
Some static checkers have options to warn when function returns are ignored (and then options to annotate a function whose returns are often ignored). Gcc has an option to mark a function as requiring the return value be used (__attribute__((warn_unused_result))) - but it only works if the return type doesn't have a destructor :-(.
Ignoring the return value of a function is perfectly valid. Take this for example:
printf("hello\n");
We're ignoring the return value of printf here, which returns the number of characters printed. In most cases, you don't care how many characters are printed. If compilers warned about this, everyone's code would show tons of warnings.
This actually a specific case of ignoring the value of an expression, where in this case the value of the expression is the return value of a function.
Similarly, if you do this:
i++;
You have an expression whose value is discarded (i.e. the value of i before being incremented), however the ++ operator still increments the variable.
An assignment is also an expression:
i = j = k;
Here, you have two assignment expressions. One is j = k, whose value is the value of k (which was just assigned to j). This value is then used as the right hand side an another assignment to i. The value of the i = (j = k) expression is then discarded.
This is very different from not returning a value from a non-void function. In that case, the value returned by the function is undefined, and attempting to use that value results in undefined behavior.
There is nothing undefined about ignoring the value of an expression.
The short reason it is allowed is because that's what the standard specifies.
The statement
change_i(10);
discards the value returned by change_i().
The longer reason is that most expressions both have an effect and produce a result. So
i = change_i(10);
will set i to be 8, but the assignment expression itself also has a result of 8. This is why (if j is of type int)
j = i = change_i(10);
will cause both j and i to have the value of 8. This sort of logic can continue indefinitely - which is why expressions can be chained, such as k = i = j = 10. So - from a language perspective - it does not make sense to require that a value returned by a function is assigned to a variable.
If you want to explicitly discard the result of a function call, it is possible to do
(void)change_i(10);
and a statement like
j = (void)change_i(10);
will not compile, typically due to a mismatch of types (an int cannot be assigned the value of something of type void).
All that said, several compilers (and static code analysers) can actually be configured to give a warning if the caller does not use a value returned by a function. Such warnings are turned off by default - so it is necessary to compile with appropriate settings (e.g. command line options).
I've been using C/C++ for about three years
I can suppose that during these three years you used standard C function printf. For example
#include <stdio.h>
int main( void )
{
printf( "Hello World!\n" );
}
The function has return type that differs from void. However I am sure that in most cases you did not use the return value of the function.:)
If to require that the compiler would issue an error when the return value of a function is not used then the code similar to the shown above would not compile because the compiler does not have an access to the source code of the function and can not determine whether the function has a side effect.:)
Consider another standard C functions - string functions.
For example function strcpy is declared like
char * strcpy( char *destination, const char *source );
If you have for example the following character arrays
char source[] = "Hello World!";
char destination[sizeof( source )];
then the function usually is called like
strcpy( destination, source );
There is no sense to use its return value when you need just to copy a string. Moreover for the shown example you even may not write
destination = strcpy( destination, source );
The compiler will issue an error.
So as you can see there is sense to ignore sometimes return values of functions.
For your own example the compiler could issue a message that the function does not have a side effect so its call is obsolete. In any case it should issue a message that the function parameter is not used.:)
Take into account that sometimes the compiler does not see a function definition that is present in some other compilation unit or in a library. So the compiler is unable to determine whether a function has a side effect,
In most cases compilers deal with function declarations. Sometimes the function definitions are not available for compilers in C and C++.
I've seen if(true) used a bunch of times.
int a = 10;
if(true){
int b = 20;
}
int c = 15;
I don't understand what the point of putting if(true) there. Does it always evaluate to true, meaning it always executes? It's not part of a function. It's just there. Does it have to do with memory allocation?
This is equivalent to :
{
int b = 20;
}
maybe someone was using if (false) then switched to if (true). if(false) makes actually sense because you are removing some code - it should not get into compiled exe, but it gets compiled by compiler - and checked for any errors.
If one is fiddling with the code, it's very easy to turn
if (true) {
// block of code
}
into
if (false) {
// block of code
}
so this is a useful construct if you often need to turn a block of code on/off. It could also be a placeholder for future changes, where the boolean value is replaced with a (template) parameter or global constant or somesuch. (or a holdover from a former change that did the reverse)
I would like to know the difference between functions that return a value and functions that set a value to a pointer, for example:
Pointer:
int myVal;
ptr_multiply(5, 5, &myVal);
cout << myVal << endl; //Output: 25
Return:
int myVal = rtn_multiply(5, 5);
cout << myVal << endl; //Output: 25
My question focuses in what method to choose when creating functions and why, as well as what advantages/disadvantages can we find in each of them.
Readability is the main reason functions typically return what you expect them to return. However, as this is highly subjective, I suggest you strive for consistency within your project.
When you want a function to return multiple things and not group them all together in a structure just so you can return them, an alternative is to return them in output parameters.
If you have big pieces of data to return, then you might come across to performance-bottlenceks. The reason is that that the returning value must be copied.
But in the most cases you don't have to worry about that, because modern compilers are capable of auto-inline things like that.
Side note: In C++ try to avoid naked pointers as much as possible (use references, smart-pointers)
One advantage to use the "pointer" method is that you can have multiple "return" values by passing in non-const references or pointers. For example:
int output1;
int output2;
get_values("input", &output1, &output2)
You can return a success/failure:
int v = -1;
if(ToInt("wibble",&v)){
// do something with v
}
Would fail as "wibble" can't be converted to an int.
The other useful thing is that the function doesn't have to change v:
int v = previousValue;
UpdateIfNewValueFound( &v )
Return the value. With modern compilers there should be almost no difference in performance between the two, but returning the value has several advantages:
By definition, it's what a function should do (i.e. a function maps from a domain to a codomain).
It's self-documenting; if I'm using an unfamiliar API, unless there is good documentation, it can get confusing what is input/output if values are returned in the parameter set. With a returned value there is no ambiguity, and requires less documenting.
It's easier to use - can half the number of lines needed! Compare
int r = f();
to
int r;
f(&r);
It could make you a better programmer; you have to put more effort into returning multiple values from a function (e.g. via a struct or pair, as opposed to adding another parameter). If you find you need to do this often, the additional effort may force you to think more carefully about your code design - it's usually better for a function to just do/return one thing.
Another difference is stack or heap.
A return-value lies on top of the stack. The pointer-variant lies in heap.
For instance (sensless recursive code to demonstrate return on stack):
typedef std::array<int,1000> KByte;
KByte tmp;
KByte f(int nr) {
if (nr == 1) { tmp[nr]=nr; return tmp; }
else { tmp[nr]=nr; return f(nr-1); };
}
void f2(int nr, KByte& ret) {
if (nr == 1) { ret[1]=1; }
else { ret[nr]=nr; f2( nr-1, ret ); }
};
Calling
KByte t = f(999); /* Stack error */
shoud give you an stack-size error, since 1000 KByte (1GB) on the stack is to much.
Calling
KByte t2;
f2( 999, t2 );
should work without stack problem. (It also uses recursion depth 1000, but does not lie the return value on the stack.
There's an interesting optimization problem I'm facing.
In a large code base, consisting of a large number of classes, in many places the value of a non-constant global (=file scope) variable is very often used/examined and the unnecessary memory accesses of this variable are to be avoided.
This variable is initialized once, but because of the complexity of its initialization and the need to call a number of functions, it cannot be initialized like this, before execution of main():
unsigned size = 1000;
int main()
{
// some code
}
or
unsigned size = CalculateSize();
int main()
{
// some code
}
Instead it has to be initialized like this:
unsigned size;
int main()
{
// some code
size = CalculateSize();
// lots of code (statically/dynamically created class objects, whatnot)
// that makes use of "size"
return 0;
}
Just because size isn't a constant and it is global (=file scope) and the code is large and complex, the compiler is unable to infer that size never changes after size = CalculateSize();. The compiler generates code that fetches and refetches the value of size from the variable and can't "cache" it in a register or in a local (on-stack) variable that's likely to be in the CPU's d-cache together with other frequently accessed local variables.
So, if I have something like the following (a made-up example for illustrative purposes):
size = CalculateSize();
if (size > 200) blah1();
blah2();
if (size > 200) blah3();
The compiler thinks that blah1() and blah2() may change size and it generates a memory read from size in if (size > 200) blah3();.
I'd like to avoid that extra read whenever and wherever possible.
Obviously, hacks like this:
const unsigned size = 0;
int main()
{
// some code
*(unsigned*)&size = CalculateSize();
// lots more code
}
won't do as they invoke undefined behavior.
The question is how to inform the compiler that it can "cache" the value of size once size = CalculateSize(); has been performed and do it without invoking undefined behavior, unspecified behavior and, hopefully, implementation-specific behavior.
This is needed for C++03 and g++ (4.x.x). C++11 may or may not be an option, I'm not sure, I'm trying to avoid using advanced/modern C++ features to stay within the coding guidelines and predefined toolset.
So far I've only come up with a hack to create a constant copy of size within every class that's using it and use the copy, something like this (decltype makes it C++11, but we can do without decltype):
#include <iostream>
using namespace std;
volatile unsigned initValue = 255;
unsigned size;
#define CACHE_VAL(name) \
const struct CachedVal ## name \
{ \
CachedVal ## name() { this->val = ::name; } \
decltype(::name) val; \
} _CachedVal ## name;
#define CACHED(name) \
_CachedVal ## name . val
class C
{
public:
C() { cout << CACHED(size) << endl; }
CACHE_VAL(size);
};
int main()
{
size = initValue;
C c;
return 0;
}
The above may only help up to a point. Are there better and more suggestive-to-the-compiler alternatives that are legal C++? Hoping for a minimally intrusive (source-code-wise) solution.
UPDATE: To make it a bit more clear, this is in a performance-sensitive application. It's not that I'm trying to get rid of unnecessary reads of that particular variable out of whim. I'm trying to let/make the compiler produce more optimal code. Any solution that involves reading/writing another variable as often as size and any additional code in the solution (especially with branching and conditional branching) executed as often as size is referred to is also going to affect the performance. I don't want to win in one place only to lose the same or even more in another place.
Here's a related non-solution, causing UB (at least in C).
There's the register keyword in C++ which tells the compiler you plan on using a variable a lot. Don't know about the compiler you're using, but most of the modern compilers do that for the users, adding a variable into the registry if needed. You can also declare the variable as constant and initialize it using const_cast.
what of:
const unsigned getSize( void )
{
static const unsigned size = calculateSize();
return size;
}
This will delay the initialization of size until the first call to getSize(), but still keep it const.
GCC 4.8.2
#include <iostream>
unsigned calculate() {
std::cout<<"calculate()\n";
return 42;
}
const unsigned mySize() {
std::cout<<"mySize()\n";
static const unsigned someSize = calculate();
return someSize;
}
int main() {
std::cout<<"main()\n";
mySize();
}
prints:
main()
mySize()
calculate()
on GCC 4.8.0
Checking for whether it has been initialized already or not will be almost fully mitigated by the branch predictor. You will end up having one false and a quadrillion trues afterwards.
Yes, you will still have to access that state after the pipeline has been basically built, potentially wreaking havoc in the caches, but you can't be sure unless you profile.
Also, compiler can likely do some extra magic for you (and it is what you're looking for), so I suggest you first compile and profile with this approach before discarding it entirely.
First of all: I know that most optimization bugs are due to programming errors or relying on facts which may change depending on optimization settings (floating point values, multithreading issues, ...).
However I experienced a very hard to find bug and am somewhat unsure if there is any way to prevent these kind of errors from happening without turning the optimization off. Am I missing something? Could this really be an optimizer bug? Here's a simplified example:
struct Data {
int a;
int b;
double c;
};
struct Test {
void optimizeMe();
Data m_data;
};
void Test::optimizeMe() {
Data * pData; // Note that this pointer is not initialized!
bool first = true;
for (int i = 0; i < 3; ++i) {
if (first) {
first = false;
pData = &m_data;
pData->a = i * 10;
pData->b = i * pData->a;
pData->c = pData->b / 2;
} else {
pData->a = ++i;
} // end if
} // end for
};
int main(int argc, char *argv[]) {
Test test;
test.optimizeMe();
return 0;
}
The real program of course has a lot more to do than this. But it all boils down to the fact that instead of accessing m_data directly, a (previously unitialized) pointer is being used. As soon as I add enough statements to the if (first)-part, the optimizer seems to change the code to something along these lines:
if (first) {
first = false;
// pData-assignment has been removed!
m_data.a = i * 10;
m_data.b = i * m_data.a;
m_data.c = m_data.b / m_data.a;
} else {
pData->a = ++i; // This will crash - pData is not set yet.
} // end if
As you can see, it replaces the unnecessary pointer dereference with a direct write to the member struct. However it does not do this in the else-branch. It also removes the pData-assignment. Since the pointer is now still unitialized, the program will crash in the else-branch.
Of course there are various things which could be improved here, so you might blame it on the programmer:
Forget about the pointer and do what the optimizer does - use m_data directly.
Initialize pData to nullptr - that way the optimizer knows that the else-branch will fail if the pointer is never assigned. At least it seems to solve the problem in my test-environment.
Move the pointer assignment in front of the loop (effectively initializing pData with &m_data, which then could also be a reference instead of a pointer (for good measure). This makes sense because pData is needed in all cases so there is no reason to do this inside the loop.
The code is obviously smelly, to say the least, and I'm not trying to "blame" the optimizer for doing this. But I'm asking: What am I doing wrong? The program might be ugly, but it's valid code...
I should add that I'm using VS2012 with C++/CLI and v110_xp-Toolset. Optimization is set to /O2. Please also note that if you really want to reproduce the problem (that's not really the point of this question though) you need to play around with the complexity of the program. This is a very simplified example and the optimizer sometimes doesn't remove the pointer assignment. Hiding &m_data behind a function seems to "help".
EDIT:
Q: How do I know that the compiler is optimizing it to something like the example provided?
A: I'm not very good at reading assembler, I have looked at it however and have made 3 observations which make me believe that it's behaving this way:
As soon as optimization kicks in (adding more assignments usually does the trick) the pointer assignment has no associated assembler statement. It also hasn't been moved up to the declaration, so it's really left uninitialized it seems (at least to me).
In cases where the program crashes, the debugger skips the assignment statement. In cases where the program runs without problems, the debugger stops there.
If I watch the content of pData and the content of m_data while debugging, it clearly shows that all assignments in the if-branch have an effect on m_data and m_data receives the correct values. The pointer itself it still pointing to the same uninitialized value it had from the beginning. Therefore I have to assume that it is in fact not using the pointer to make the assignments at all.
Q: Does it have to do anything with i (Loop unrolling)?
A: No, the actual program actually uses do { ... } while() to loop over a SQL SELECT-resultset so the iteration count is completely runtime-specific and cannot be predetermined by the compiler.
It sure looks like an bug to me. It's fine for the optimizer to eliminate the unnecessary redirection, but it should not eliminate the assignment to pData.
Of course, you can work around the problem by assigning to pData before the loop (at least in this simple example). I gather that the problem in your actual code isn't as easily resolved.
I also vote for an optimizer bug if it is really reproducible in this example. To overrule the optimizer you could try to declare pData as volatile.