Is it safe to take the address of a temporary? - c++

In my program, I would like to take the address of a temporary. Here is an example:
#include <iostream>
struct Number {
int value;
Number(int n) {
value = n;
}
};
void print(Number *number) {
std::cout << number->value << std::endl;
}
int main() {
Number example(123);
print(&example);
print(&Number(456)); // Is this safe and reliable?
}
This would output:
123
456
To compile, the -fpermissive flag is requied.
Here is my question: is this safe and reliable? In what possible case could something go wrong?

If your definition of "safe and reliable" includes "will compile and produce the same results if the compiler is updated" then your example is invalid.
Your example is ill-formed in all C++ standards.
This means, even if a compiler can be coerced to accept it now, there is no guarantee that a future update of your compiler will accept it or, if the compiler does accept the code, will produce the same desired effect.
Most compiler vendors have form for supporting non-standard features in compilers, and either removing or altering support of those features in later releases of the compiler.
Consider changing your function so it accepts a const Number & rather than a pointer. A const reference CAN be implicitly bound to a temporary without needing to bludgeon the compiler into submission (e.g. with command line options). A non-const reference cannot.

&Number(456) is an error because the built-in & operator cannot be applied to an rvalue. Since it is an error, it is neither safe nor reliable. "What could go wrong" is that the code could be rejected and/or behave unexpectedly by a compiler which follows the C++ Standard. You are relying on your compiler supporting some C++-like dialect in which this code is defined.
You can output the address of the temporary object in various ways. For example add a member function auto operator&() { return this; } . The overloaded operator& can be applied to prvalues of class type.
Another way would be to have a function that is like the opposite of move:
template<typename T>
T& make_lvalue(T&& n)
{
return n;
}
and then you can do print(&make_lvalue(Number(456)));
If you are feeling evil, you could make a global template overload of operator&.

This is fine but..
Number *a;
print(a); // this would be a null ptr error
How I would change it is
void print(const Number num) // make the paramater const so it doesnt change
{
std::cout << num.value << std::endl; // note the . instead of -> cuz this is a reference not a pointer
}
You would remove the "&" from your code like:
Number example(123);
print(example);
print(Number(456));
and if you need to pass a pointer you just put a "*" to dereference it.
chasester

Related

Can a void pointer point to a lambda function?

Assigning a function pointer to a void pointer,
double f_dummy(double x) { return x; }
...
void *pv = f_dummy; //compilation error
is illegal as explained in this FAQ. The answer, however, closes with the statement :
Please do not email me if the above seems to work on your particular version of your particular compiler on your particular operating system. I don’t care. It’s illegal, period.
Edit : As a warning to others, I did encounter this "seems to work" behavior, through a case of inheritance involving class templates. No compiler warning, no unexpected run-time behavior.
This tickles my OCD bone and makes me wonder if what I've been doing, e.g.,
...
auto l_func = [](double x){ return f_dummy(x); };
void *pv = &l_func;
auto pl = static_cast<decltype(&l_func)>(pv);
cout << (*pl)(5.) << endl;
which compiles and runs cleanly (g++ -std=c++11 -Wall), is truly legal. Is it?
Yes, it's legal, because:
pointers to objects may be cast to void* and back again;
l_func is an object (a functor, with unspecified class type) — that's how lambdas are implemented, by standard mandate.
The FAQ text you cite is unrelated, as it refers to pointers to functions. _yourUnspecifiedLambdaType::operator() is the equivalent* function, but you're not doing anything with that here.
* Well, it's not even equivalent, because it's a member function!

Address of return value of method

I have a get-method that returns a value:
int Foo::getValue() const
{
return value_;
}
I'm using the following code to write this value to a binary file:
void Bar::write(const Foo& foo)
{
/* some code... */
file_.write(reinterpret_cast<char*>(&foo.getValue()), sizeof(int));
}
And it seems that everything works well. But I am not sure about that &foo.getValue() thing. Will it always return an address of return value of getValue() or are there any pitfalls?
EDIT1: I dont want to create a temporary var for this.
EDIT2: Yes, it compiles and works fine.
EDIT3: write is a ostream::write
EDIT4: With /Wall and /Za it will not compile: error C2102: '&' requires l-value
The standard forbids you to take the address of an rvalue: https://stackoverflow.com/a/28459180/2642059 A compiler that is not standard compliant may allow this behavior, but assuredly that is not behavior that will be cross platform, nor is it guaranteed to succeed even between updates to the compiler that may more closely align it with the C++ standard.
Since you are not programming for a specific compiler, but for C++, finding something that works in a specific compiler should not be your objective. Finding a way to accomplish this within the standard would be preferable.
A couple easy options for doing that would be:
Turn it into an lvalue by assigning it to a temporary value. They're free! The compiler will optimize them right out
Change the return of getValue to const int& this will allow you to work with an lvalue. Since ints are typically copied by value this probably will not have repercussions in your code base, but it could
Create another method which could directly return (const char*)&value_, you could get in trouble abusing this one though so be careful
Microsoft Compiler for whatever reason has a `"feature" - it implicitly converts temporary to lvalue. You can check it by this code:
int &ref = foo.getValue();
this code as well as your should not compile. Proper code would be:
void Bar::write(const Foo& foo)
{
/* some code... */
int temp = foo.getValue();
file_.write(static_cast<const char*>(&temp), sizeof(int));
}

Strange behavior in casting of function pointers in C++

I have recently encountered a behavior in C++ regarding function pointers, that I can't fully understand. I asked Google for help as well as some of my more experienced colleagues, but even they couldn't help.
The following code showcases this mystique behavior:
class MyClass{
private:
int i;
public:
MyClass(): i(0) {}
MyClass(int i): i(i) {}
void PrintText() const { std::cout << "some text " << std::endl;}
};
typedef void (*MyFunction) (void*);
void func(MyClass& mc){
mc.PrintText();
}
int main(){
void* v_mc = new MyClass;
MyFunction f = (MyFunction) func; //It works!
f(v_mc); //It works correctly!!!
return 0;
}
So, first I define a simple class that will be used later (especially, it's member method PrintText). Then, I define name object void (*) (void*) as MyFunction - a pointer to function that has one void* parameter and doesn't return a value.
After that, I define function func() that accepts a reference to MyClass object and calls its method PrintText.
And finally, magic happens in main function. I dynamically allocate memory for new MyClass object casting the returned pointer to void*. Then, I cast pointer to func() function to MyFunction pointer - I didn't expect this to compile at all but it does.
And finally, I call this new object with a void* argument even though underlying function (func()) accepts reference to MyClass object. And everything works correctly!
I tried compiling this code with both Visual Studio 2010 (Windows) and XCode 5 (OSX) and it works in the same manner - no warnings are reported whatsoever. I imagine the reason why this works is that C++ references are actually implemented as pointers behind the scenes but this is not an explanation.
I hope someone can explain this behavior.
The formal explanation is simple: undefined behaviour is undefined. When you call a function through a pointer to a different function type, it's undefined behaviour and the program can legally do anything (crash, appear to work, order pizza online ... anyting goes).
You can try reasoning about why the behaviour you're experiencing happens. It's probably a combination of one or more of these factors:
Your compiler internally implements references as pointers.
On your platform, all pointers have the same size and binary representation.
Since PrintText() doesn't access *this at all, the compiler can effectively ignore the value of mc altogether and just call the PrintText() function inside func.
However, you must remember that while you're currently experiencing the behaviour you've described on your current platform, compiler version and under this phase of the moon, this could change at any time for no apparent reason whatsoever (such as a change in surrounding code triggering different optimisations). Remember that undefined behaviour is simply undefined.
As to why you can cast &func to MyFunction - the standard explicitly allows that (with a reinterpret_cast, to which the C-style cast translates in this context). You can legally cast a pointer to function to any other pointer to function type. However, pretty much the only thing you can legally do with it is move it around or cast it back to the original type. As I said above, if you call through a function pointer of the wrong type, it's undefined behaviour.
I hope someone can explain this behavior.
The behaviour is undefined.
MyFunction f = (MyFunction) func; //It works!
It "works" because you use c-style cast which has the same effect as reinterpret_cast in this case I think. If you had used static_cast or simply not cast at all, the compiler would have warned of your mistake and failed. When you call the wrongly interpreted function pointer, you get undefined behaviour.
It's only by chance that it works. Compilers are not guaranteed to make it work. Behind the scenes, your compiler is treating the reference as a pointer, so your alternative function signature just happens to work.
I'm sorry, to me isn't clear why you call this a strange behavior, I don't see a undefined behavior that depends on moon cycle here, is the way to use function pointers in C.
Adding some debug output you may see that the pointer to the object remain the same in all the calls.
void PrintText() const { std::cout << "some text " << this << std::endl;}
^^^^
void func(MyClass& mc){
std::cout << (void *)&mc << std::endl;
^^^
void *v_mc = new MyClass;
std::cout << (void *)v_mc << std::endl;
^^^^

Why doesn't void take a void value in C++?

I'm curious why C++ does not define void via :
typedef struct { } void;
I.e. what is the value in a type that cannot be instantiated, even if that installation must produce no code?
If we use gcc -O3 -S, then both the following produce identical assembler :
int main() { return 0; }
and
template <class T> T f(T a) { }
typedef struct { } moo;
int main() { moo a; f(a); return 0; }
This makes perfect sense. A struct { } simply takes an empty value, easy enough to optimize away. In fact, the strange part is that they produce different code without the -O3.
You cannot however pull this same trick with simply typedef void moo because void cannot assume any value, not even an empty one. Does this distinction have any utility?
There are various other strongly typed languages like Haskell, and presumably the MLs, that have a value for their void type, but offer no valueless types overtly, although some posses native pointer types, which act like void *.
I see the rationale for void being unable to be instantiated coming from the C roots of C++. In the old gory days, type safety wasn't that big a deal and void*s were constantly passed around. However, you could always be looking at code that does not literally say void* (due to typedefs, macros, and in C++, templates) but still means it.
It is a tiny bit of safety if you cannot dereference a void* but have to cast it to a pointer to a proper type, first. Whether you accomplish that by using an incomplete type as Ben Voigt suggests, or if you use the built-in void type doesn't matter. You're protected from incorrectly guessing that you are dealing with a type, which you are not.
Yes, void introduces annoying special cases, especially when designing templates. But it's a good thing (i.e. intentional) that the compiler doesn't silently accept attempts to instantiate void.
Because that wouldn't make void an incomplete type, now would it?
Try your example code again with:
struct x; // incomplete
typedef x moo;
Why should void be an incomplete type?
There are many reasons.
The simplest is this: moo FuncName(...) must still return something. Whether it is a neutral value, whether it is the "not a value value", or whatever; it still must say return value;, where value is some actual value. It must say return moo();.
Why write a function that technically returns something, when it isn't actually returning something? The compiler can't optimize the return out, because it's returning a value of a complete type. The caller might actually use it.
C++ isn't all templates, you know. The compiler doesn't necessarily have the knowledge to throw everything away. It often has to perform in-function optimizations that have no knowledge of the external use of that code.
void in this case means "I don't return anything." There is a fundamental difference between that and "I return a meaningless value." It is legal to do this:
moo FuncName(...) { return moo(); }
moo x = FuncName(...);
This is at best misleading. A cursory scan suggests that a value is being returned and stored. The identifier x now has a value and can be used for something.
Whereas this:
void FuncName(...) {}
void x = FuncName(...);
is a compiler error. So is this:
void FuncName(...) {}
moo x = FuncName(...);
It's clear what's going on: FuncName has no return value.
Even if you were designing C++ from scratch, with no hold-overs from C, you would still need some keyword to indicate the difference between a function that returns a value and one that does not.
Furthermore, void* is special in part because void is not a complete type. Because the standard mandates that it isn't a complete type, the concept of a void* can mean "pointer to untyped memory." This has specialized casting semantics. Pointers to typed memory can be implicitly cast to untyped memory. Pointers to untyped memory can be explicitly cast back to the typed pointer that it used to be.
If you used moo* instead, then the semantics get weird. You have a pointer to typed memory. Currently, C++ defines casting between unrelated typed pointers (except for certain special cases) to be undefined behavior. Now the standard has to add another exception for the moo type. It has to say what happens when you do this:
moo *m = new moo;
*moo;
With void, this is a compiler error. What is it with moo? It's still useless and meaningless, but the compiler has to allow it.
To be honest, I would say that the better question would be "Why should void be a complete type?"

error: lvalue required while operator overloading ++/-- etc

I transferred my code to Ubuntu 4.4.1 g++ compiler. While overloading operator ++ (int) as below, it throws error for (T*), but works fine for (T*&). In my earlier version (linux-64, but don't remember exact version) it was working fine with (T*) also.
Any reason, why ?
template<typename T>
struct Wrap
{
void *p; // Actually 'p' comes from a non-template base class
Wrap<T>& operator ++ ()
{
((T*)p) ++; // throws error; if changed to (T*&) then ok!
return *this;
}
// ...
};
int main ()
{
Wrap<int> c;
++c; // calling prefix increment
}
A result of a type-cast is not an lvalue, so it cannot be assigned to and (built-in) ++ is a form of assignment. It was a bug in the compiler if it ever worked.
With reference it compiles (in efect it's the same as *(T**)&p), but due to aliasing rules (compiler may assume that pointers (and references) of different types don't point to the same object) it is formally invalid, though it will work on all known compilers.
The cleanest way it to:
p = static_cast<void *>(static_cast<T *>(p) + 1)
(never use C-style cast in C++) and rely on the compiler being able to compile it exactly the same way as ++. However if you have the template argument available when defining the pointer (in the sample code you do), it's much better to just use properly typed pointer (I'd say it would also work with member pointers, but they don't have meaningful ++).
Looks like you mixing up your prefix and postfix increment signatures. Also, why use a void* if you know your type is T ?
See below for appropriate signatures:
http://www.codeguru.com/forum/showthread.php?t=231051