I noticed I don't get any compiler errors when I accidentally forget to return from a function that is supposed to return a reference. I wrote some small tests to see what actually happens and I got more confused than anything.
struct Foo
{
int x;
Foo() {
x = 3;
}
};
Foo* foo = new Foo;
Foo& test(bool flag) {
if (flag)
return *foo;
}
If test() doesn't (explicitly) return a value, I will still get something returned. However the Foo object that is returned is not initialized using the default constructor — that's because x is different from 3 in the non-explicitly returned value.
What is actually happening when you don't return a reference? If this is a feature, is it safe to use it as a means to return dummy objects in case errors occur, as opposed to returning a null pointer. (See example below.)
class FooFactory
{
// Return reference...
Foo& createFooRef() {
Foo* foo = new Foo;
bool success = foo->load();
if (success)
return *foo;
// Implicit (and safe?) return value on failure?
}
// ... as opposed to returning a pointer.
Foo* createFooPtr() {
Foo* foo = new foo;
bool success = foo->load();
if (success)
return foo;
else
return 0;
}
// Yes, I am aware of the memory leaks,
// but that's not the point of the example.
Most compilers will give you a warning about this, but you may have to crank up the warning level of the compiler to see it.
No, this is not safe. It is bad. It may lead to stack corruption by just returning whatever happens to be on the stack at the time. As you've already seen, it does not use a constructor for you. If you want a default constructed object, you have to do that yourself (but be careful about returning a reference to a temporary object. That's also bad).
The usual way to lower references in compilers is to pointers. For a reference-returning function, it will mean you get an arbitrary address represented, whatever was in the register or stack slot used for the return value.
Formally in the language, the effects are undefined.
This is undefined behaviour, and infinite bad things may happen, or indeed, may not happen, or might happen sometimes, or might simultaneously happen and not happen if it doesn't like you, or send engineers from Microsoft to your house to beat you over the head with a baseball bat.
The described behaviour is not limited to functions that returns references. The following code will also compile:
int func1( int i )
{
if( i )
return 3; // C4715 warning, nothing returned if i == 0
}
I'm not sure why they generate just a warning, not an error (there might be an option in settings to turn it into error), but you will get undefined behaviour if you call such a function
References are typically just syntactic sugar for pointers, so the return is going to grab a pointer's worth of bytes from the stack for the return value. If you aren't giving it that it will just grab garbage.
I had to use the function and then add -Wall to get g++ to complain:
g++ -Wall foo.cc
foo.cc: In member function 'Foo& FooFactory::createFooRef()':
foo.cc:19: warning: control reaches end of non-void function
Have you tried compiling with /O1 optimisations or greater on and treat warnings as errors? That might fail. I remember something along those lines happening in GCC 4.1. You could forget to return the reference in debug mode, but the reference would return; as soon as you put any optimisations on it would still compile, but not return the reference. When coding in a text editor (as I was in those days) it was a total pain and a huge surprise to me.
Related
In visual studio you can invoke function on already deleted object:
class Foo {
void bar() {
...
}
};
you can actually execute following code without errors:
Foo * foo = new Foo();
delete foo;
foo->bar();
and as long as code in Foo::bar doesn't do anything with this pointer. My first question is, is this undefined behavior that happens to work or is it according to standard?
Second question:
If we alter code to:
Foo * foo = new Foo();
delete foo;
foo = nullptr;
foo->bar();
we can in Foo::bar use following check
if (this == nullptr) {
...
}
in order to determine if we operate on valid object. While it doesn't seem like good idea to do this, is there any architecture/design were this could be useful?
Both uses are just plain UB.
if (this == nullptr) may even be optimized away by the compiler as this is never nullptr in legal code. Clang warns about this btw.
Update: As of gcc 6, gcc actually does optimize based on assuming this != nullptr. They also added a warning. See it live.
If a method do not execute any class member it should be a static one. A static method can be called always without any object and the compiler gives an error if this is not true.
The check
if ( this )
looks very very dirty to me. Only for test purpose a assert sounds helpful. But if I must fear that a method can be called without object, there is no chance to get save that the pointer ( this ) is set valid to nullptr. This is bug shifting and not a solution.
And if the method is a virtual one, the check for this==nullptr comes to late because the vtable ptr could not be found.
The design of a program should handle new/delete in a proper way. Maybe the use of any kind of smart pointers can help.
foo->bar() always dereferences foo.
Dereferencing a pointer after deleting it gives undefined behaviour. If Visual Studio happens to give no error, that is happenstance. Any result is permitted from undefined behaviour, including giving no apparent error.
Setting foo to be nullptr and then calling foo->bar() also gives undefined behaviour, because it dereferences a NULL pointer. Testing this == nullptr inside Foo::bar() does not change that, because it is the caller that has exhibited undefined behaviour even before Foo::bar() has been called.
foo->bar()
this statement means decode the address in foo. and put it into the call stack, and then put the variable content of bar to the call stack. Lastly, execute the function.
If the ::bar() function is completely empty. It is OK.
Otherwise, even you just declare some variable. The address of *foo is already dirty by your function call.
1) If the foo == nullptr. 0x0000000 is a read only section, your program will crash, or throw exception when your main is end.
2) If the foo != nullptr, but it is deleted. The heap will corrupted, and the memory barrier may detect your action, it may crash
3) If the foo != nullptr, and it is stack variable. The stack is dirty and it will crash.
It might be obvious for who knows the background magic, but I could not understand how below code is giving correct output. I expected a runtime error. Please help.
class a
{
public:
void print()
{
cout<<"Hello\n"<<endl;
int d = 100;
cout<<d<<endl;
}
int val;
};
int main()
{
a* ptr;
ptr->print();
return SUCCESS;
}
OUTPUT is as below :
Hello
100
There is no magic - your code has undefined behavior. In your code you do not access ptr which is implicitly passed to print() as this pointer, that is why no error happen.
It may happen in several other cases:
Accessing fields of a instance. It will require to read memory *(this + field_offset) which will cause runtime error.
Accessing virtual methods. Implementations known to me use vtable to do that, which is usually stored as first pointer in object space, so pointer to vtable would be same as this, so: vtable = *this
Other cases, depending on compiler and platform
NOTE: type conversion is omitted from examples with this
a::print is a not a virtual method, hence it is just a normal function that has an extra argument to receive the this pointer. Since the method never uses the this pointer, the fact that it is uninitialized doesn't turn into a memory access error or other failure. Declaring a::print static will still compile in this case since it doesn't use the this pointer. Declaring a::print virtual or accessing this inside the method will likely lead to the program crashing, at least under some circumstances.
The behavior is still undefined and it is an ill-formed program, but as it stands now it is very likely to work deterministically on most systems. In general C++ does not give runtime errors for such cases, but if you compile with e.g. "clang++ -Wall" a warning indicating the uninitialized variable will be given. (And there are tools such as clang's asan which will go further in diagnosing such errors.)
My colleague recently compiled our program in Windows, and discovered a bug of the sort:
std::string a = "hello ";
std::string b = "world";
const char *p = (a+b).c_str();
printf("%s\n", p);
which for some reason did not crash in our Linux executables.
None of our compilers give any kind of warning, so we are now worried that this error might exist in the code.
Although we can grep for c_str() occurrences and do a visual inspection, there is a possibility that one might have also done the following:
struct I {
int num;
I() { num=0; }
};
struct X {
I *m;
X() { m = new I; }
~X() { delete m; }
I get() { return *m; } // version 1, or
I& get() { return *m; } // version 2
};
and accessed it like:
I& a = X().get(); // will get a reference to a temporary, or a valid copy?
cout << a.num;
instead of :
cout << X().get().num;
which is safe (isn't it?)
Question: Is there a way I can catch such errors (perhaps using the compiler, or even an assertion) ?
I need to be sure that if author of struct X changes get() between version 1 and 2 that the program will warn for the error
Simple answer: In general you cannot catch those errors, and the reason is that there are similar constructs that might be perfectly fine, so the compiler would have to know the semantics of all the functions to be able to warn you.
In simpler cases, like obtaining the address of a temporary, many compilers already warn you, but in the general case, it is quite difficult if not impossible for the compiler to know.
For some similar example to the .c_str() consider:
std::vector< const char * > v;
v.push_back( "Hi" );
const char* p = *v.begin();
The call to begin returns a temporary, similar to the expression (a+b), and you are calling a member function of that temporary (operator*) that returns a const char*, which is quite similar to your original case (from the point of view of the types involved). The problem is that in this case the pointee is still valid after the call, while in yours (.c_str()) it isn't, but it is part of the semantics of the operation, not the syntax that the compiler can check for you. The same goes for the .get() example, the compiler does not know if the returned reference is to an object that will be valid after the expression or not.
All these fall under the category of Undefined Behavior.
Check out this question's solution, I think it does something similar to what you're looking for:
C++ catching dangling reference
There are runtime based solutions which instrument the code to check
invalid pointer accesses. I've only used mudflap so far (which is
integrated in GCC since version 4.0). mudflap tries to track each
pointer (and reference) in the code and checks each access if the
pointer/reference actually points to an alive object of its base type.
Here is an example: {...}
Lets say you have something like this:
int& refint;
int* foo =0;
refint = *foo;
How could you verify if the reference is NULL to avoid a crash?
You can't late-initialize a reference like that. It has to be initialized when it's declared.
On Visual C++ I get
error C2530: 'refint' : references
must be initialized
with your code.
If you 'fix' the code, the crash (strictly, undefined behaviour) happens at reference usage time in VC++ v10.
int* foo = 0;
int& refint(*foo);
int i(refint); // access violation here
The way to make this safe is to check the pointer at reference initialization or assignment time.
int* foo =0;
if (foo)
{
int& refint(*foo);
int i(refint);
}
though that still does not guarantee foo points to usable memory, nor that it remains so while the reference is in scope.
You don't, by the time you have a "null" reference you already have undefined behaviour. You should always check whether a pointer is null before trying to form a reference by dereferencing the pointer.
(Your code is illegal; you can't create an uninitialized reference and try and bind it by assigning it; you can only bind it during initialization.)
In general, you can't.
Whoever "creates a null reference" (or tries to, I should say) has already invoked undefined behavior, so the code might (or might not) crash before you get a chance to check anything.
Whoever created the reference should have done:
int *foo = 0;
if (foo) {
int &refint = *foo;
... use refint for something ...
}
Normally it's considered the caller's problem if they've written *foo when foo is null, and it's not one function's responsibility to check for that kind of error in the code of other functions. But you could litter things like assert(&refint); through your code. They might help catch errors made by your callers, since after all for any function you write there's a reasonable chance the caller is yourself.
All the answers above are correct, but if for some reason you want to do this I thought at least one person should provide an answer. I am currently trying to track down a bad reference in some source code and it would be useful to see if someone has deleted this reference and set it to null at some point. Hopefully this wont generate to many down votes.
#include <iostream>
int main()
{
int* foo = nullptr;
int& refint = *foo;
if(&refint == nullptr)
std::cout << "Null" << std::endl;
else
std::cout << "Value " << refint << std::endl;
}
Output:
Null
To make the above code compile, you will have to switch the order:
int* foo =0;
int& refint = *foo; // on actual PCs, this code will crash here
(There may be older processor or runtime architectures where this worked.)
....saying all of the above, if you do want to have a null reference, use boost::optional<>, works like a charm..
You don't need to, references cannot be null.
Read the manual.
In below code snippet, although pointer is not initialized the call is still made successfully
temp *ptr;
ptr->func2();
Is it due to C++ language property, or it is VC++6 compiler which is foul playing?
class temp {
public:
temp():a(9){}
int& func1()
{
return a;
}
bool func2(int arg)
{
if(arg%2==0)
return true;
return false;
}
int a;
};
int main(int argc, char **argv)
{
temp *ptr;
int a;
cin>>a;
if(ptr->func2(a))
{
cout<<"Good poniner"<<endl;
}
ptr->func1(); // Does not crash here
int crashere=ptr->func1();// But does crash here
return 0;
}
The C++ compiler doesn't prevent you from using uninitialised pointers, and although the results are undefined, it's normal for compilers in the real world to generate code that ignores the fact that the pointer is uninitialised.
It's one of the reasons why C++ is both fast and (comparatively) dangerous relative to some other languages.
The reason your call to func2 succeeds is that it doesn't touch its this pointer. The pointer value is never used, so it can't cause a problem. In func1 you do use the this pointer (to access a member variable), which is why that one crashes.
This is entirely compiler-dependent and undefined behaviour according to the standard. You shouldn't rely on this.
Call to func2() succeeds because the exact method to call is known at compile time (the call is not virtual) and the method itself doesn't dereference this pointer. So invalid this is okay.
ptr->func1(); // This works
because the compiler is instructed to return the reference to the class member. To do so it simply adds the offset of the member to the invalid value of this pointer and that produces yet another invalid pointer (reference, which is almost the same).
int crashere=ptr->func1();// Crashes here
because now the compiler is instructed to retrieve the value via that invalid reference and this crashed the program.
C++ has the notion of Undefined Behavior. Using an uninitialized pointer is a common example of such Undefined Behavior. For performance reasons, the C++ standard places no restrictions whatsoever on the possible outcome. That is to say, formatting the harddisk is perfectly acceptable.
I suspect that ptr->func2() is optimised away as it always returns true. But as Richie says, the use of the pointer is fine in this case as you;re not touching any instance data (a) and as such there is nothing to crash into.
Its not working. Its just by luck that your application is not crashing where your expecting it to crash. Its not a feature but a side-effect of the compiler which is allowing the function call to seem to work.
You can call the methods using uninitialised pointers. It will work either
ptr->func1();
or
int crashere=ptr->func1();//