Sign in to follow this  
Adam_42

Compiler behaviour quiz

Recommended Posts

Here's some example code:

 

#include <iostream>
 
using namespace std;
 
struct number { float x; };
 
number test_func(void) { static number v; return v; }
 
int main()
{
    const number one = { 1.0f };

    test_func() = one;
    test_func().x += 1.0f;
    
    cout << test_func().x << endl;
    
    return 0;
}

 

Mini quiz:

 

1. Without using a compiler look at the code. Would you expect any warnings or errors from the compiler? Why?

 

2. What would you expect the output to be if it compiled?

 

3. Now compare your results to what actually happens when you compile it. Is it what you expected?

Share this post


Link to post
Share on other sites

[spoiler]

As you've hopefully found out by now on some compilers the code doesn't produce a single error or warning. This is the result from Clang:

 

test.cpp:14:19: error: expression is not assignable
    test_func().x += 1.0f;
    ~~~~~~~~~~~~~ ^

1 error generated.

 

I was expecting at least a warning from most compilers - the code is clearly not sensible. Clang didn't even pick up the other line of code that is equally bad...
[/spoiler]

Share this post


Link to post
Share on other sites

Clang didn't even pick up the other line of code that is equally bad...

From the compiler's point of view it's not equally bad. For test_func().x += 1.0f, the compiler will see test_func() is an rvalue so test_func().x is also an rvalue, so if a primitive rvalue appears on the left side of an = then you've got a problem. However, for test_func() = one, it doesn't think of the = as a real =, it sees that the left hand side is a class type, so this is actually test_func().operator=(one). The . operator when the right hand side is a member function doesn't care if the left hand side is an rvalue, it only looks for the cv-qualifier such as const or non-const. In this case test_func() returns a non-const object so it can be bound to the compiler generated number & number::operator=(const number &) function.

Share this post


Link to post
Share on other sites
Apparently GCC catches it also. Here's my expected results before compiling and before reading others' comments:

1. Without using a compiler look at the code. Would you expect any warnings or errors from the compiler? Why?

"test_func() = one;"- Some kind of 'Assigning to r-value/temporary' warning, since test_func() isn't returning by reference.
 
Also, test_func(void) should be test_func(), no need for the 'void' there. I don't know if a warning will result. Probably something like "explicit void argument - compile with -ANSI to disable warning"
 

2. What would you expect the output to be if it compiled?

Undefined gibberish value - whatever 'static number v' initially resolves to, because it has never been assigned anything.
 

3. Now compare your results to what actually happens when you compile it. Is it what you expected?

Using GCC/MinGW 4.7.2:
 
I didn't get the warning I expected on assigning "test_func() = one;",
instead I got an *error* on on the member variable assignment version: "test_func().x += 1.0f;"
 
error: using temporary as lvalue [-fpermissive]
 
[hr]
 
I only found out yesterday that this is valid and standardized C++:
const int &refToTemp = 357;
...it just only lasts to the end of the scope that the expression is contained in. Still it's useful for avoiding a copy in some circumstances, which is why I looked it up:
//Only makes a copy if 'condition' is false.
const std::string &myString = ( ...condition... ? this->memberString : this->GetCopyOfSubStr_ReturnByValue());
this->UseString(myString);
Edited by Servant of the Lord

Share this post


Link to post
Share on other sites

Also, test_func(void) should be test_func(), no need for the 'void' there.

(void) is a perfectly standard, legal alternative to () for function declarations that aren't destructors. It's not necessary, but neither is white space in most cases. Since (void) and () have a different meaning in C, giving a warning for this would annoy quite a few people who write or use headers that are meant to be used from both C and C++. And since that includes the C standard library headers, which every C++ compiler that is also a C compiler will have, this isn't a warning you'll find very often.

Undefined gibberish value - whatever 'static number v' initially resolves to, because it has never been assigned anything.

Objects with static storage duration, which includes function local static variables, are automatically zero-initialized before any other initialization takes place (if any). Since the class type lacks any implicit or explicit non-trivial constructors and the object has no other initialization, then zero initialization is the only thing that happens in this case.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this