Sign in to follow this  
AcidZombie24

byval struct problem

Recommended Posts

Can anyone tell me why this does not work until i put const in the constructor?
struct Dummy
{
	int a;
};

class MyClass
{
public:
	MyClass(Dummy &v) //<-- this needs to be MyClass(const Dummy &v), why?
	{
	}
};

Dummy f()
{
	Dummy retbyval;
	retbyval.a=5;
	return retbyval;
}

int main()
{
	MyClass myclass(f());
	return 0;
}


[Edited by - AcidZombie24 on October 9, 2008 8:38:11 PM]

Share this post


Link to post
Share on other sites
By binding a temporary to a const reference, you effectively extend the lifetime of that temporary to that of the reference. Without the const qualifier, the temporary return by f() goes out of scope immediately after the expression in which it appears. More info.

Share this post


Link to post
Share on other sites
Quote:
Original post by Driv3MeFar
By binding a temporary to a const reference, you effectively extend the lifetime of that temporary to that of the reference. Without the const qualifier, the temporary return by f() goes out of scope immediately after the expression in which it appears. More info.


Whoops, sorry, this has nothing to do with rvalue lifetime extension. As the reference in question doesn't last beyond the lifetime of MyClass's constructor, it does not extend the lifetime of the returned object of f() in the expression:

MyClass myclass(f());

(I should probably write an article on this, this is at least the second time I've seen the misconception that const-ref-to-rvalue lifetime extension could be related to class instance lifetime.)

The problem the OP is facing is almost because rvalues cannot be implicitly converted into a non-const reference. The OP is almost certainly facing a compile issue, as it's illegal C++ -- although MSVC allows it by an extension (with warnings to that effect issued at level 4).

Share this post


Link to post
Share on other sites
i was positive it wasnt a lifetime or scope problem.
so the problem is it becomes an rvalue when returned from the function and rvalues are expected not to be modified?

so MSVC will warn me of this on warning level 4, is there a way to prevent it from warning me about silly things? (i see many silly msvc warnings that gcc -Wall and -wextra does not give)

Share this post


Link to post
Share on other sites
I guess I should try to actually answer the question while I'm replying to this thead, h-uh? [lol]

Quote:
<-- this needs to be MyClass(const Dummy &v), why?


The "obvious" reason is because it shouldn't be possible to modify v. But that just leads to the next question: And why is that?

You have to take the situation as a whole. What happens when you modify a temporary variable? Well, you modify it... and then it gets discarded, modifications and all.

It doesn't hurt so much in a case like this where it might seem obvious that the temporary results will be discarded. The reasoning becomes much more obvious with code like this:

void foo( double& var ) { var += 3.1415; } // <--- const would be necessary here too to allow this to compile (although var += ... wouldn't compile then)

int main() {
int var = 42;
foo(var); //<--- won't compile
std::cout << var << std::endl;
}



Why? The thing is, int can be converted to double. If C++ allowed this code to compile as is, what would happen? The programmer is expecting var to be modified since he's passing it to a function by non-const reference.

But since foo is operating on an implicit copy made for us -- since var is an int, not a double -- var wouldn't actually be modified. This would be a subtle bug discernible only at runtime. These can be very hard to debug.

This is why C++ instead gives you a compile error. If you don't like it, you can always explicitly tell the compiler to do it anyways:

int main() {
int var = 42;

// A local scope:
{
double var_copy = (double)var;
foo(var_copy);
}

std::cout << var << std::endl;
}


This is explicit about the copy, and thus there is no problem. From reading the function, it's clear that any modifications to var_copy would be discarded.

Hope this helps.

Share this post


Link to post
Share on other sites
Quote:
Original post by AcidZombie24
so MSVC will warn me of this on warning level 4, is there a way to prevent it from warning me about silly things?

Sure, but I should point out this isn't a silly warning like most level 4 warnings are. GCC will flat out refuse to even compile the same code, treating it as a fatal error.

But, you can either add the /wd#### flag to your compiler settings -- where #### is the same number by the C (e.g. /wd1234 for "warning C1234: You maniacs! You blew it up!").

Alternatively, if you don't want to disable the warning for the entire project, you can do:

#pragma warning( push )
#pragma warning( diable: #### )

...warning #### will be disabled for this region...

#pragma warning( pop )

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