Sign in to follow this  

Object to reference conversion (C4239)

This topic is 4075 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I just cranked my compiler up from level 3 to level 4 warnings, and there's a lot of work here. One of the warnings pertain to something that I've really relied on: warning C4239: nonstandard extension used : 'argument' : conversion from 'Class' to 'Class &'. This is generated from something like.. Function( Vector(0,0,1), 2, 1 ); ..where the compiler wants.. Vector temp(0,0,1); Function( temp, 2, 1 ); Is it safe to ignore this warning? Or should I break out my chainsaw? Just looking for opinions.

Share this post


Link to post
Share on other sites
If it is nonstandard I think your only worry is portability to other compilers and OS's. I would prefer the second option because of that and because that's what the compiler is doing for you anyway.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kest
Is it safe to ignore this warning?

It is rather rare that you want to ignore any warnings. If they could be ignored, the compiler probably wouldn't bother warning you about them.

CM

Share this post


Link to post
Share on other sites
Quote:
Original post by Absolution
If it is nonstandard I think your only worry is portability to other compilers and OS's. I would prefer the second option because of that and because that's what the compiler is doing for you anyway.

I don't mind typing it out. I was just a little worried that one of the billion places I rely on this working won't be as simple.

Quote:
Original post by scottdewald
You need to change your prototype to
void Function(const Vector &v, int, int)
When you create the Vector inlined like that, it creates a constant object that can't be modified.

My vector class does work that way. I invented the example code. But I didn't realize the const would resolve this issue. That means the majority of my code will be okay, then.

My real warning code for this situation used a class that works like a universal file-source. When objects are loaded, instead of accepting a filename, they accept a "plug". They load data from the plug, and the plug can pull that data from different sources. So my real code looks like this..

void Class::Create(Plug &plug, const Buffer *buf);
void Class::Create(const char *filename, const Buffer *buf) { return Create( Plug( filename ), buf ); }

But knowing the const rule is a big help. I don't mind declaring outside of function params for only non-const objects. Thanks for that.

Share this post


Link to post
Share on other sites
You have non-standard compliant code, temporaries and literals can only be bound to constant references, so if you still want to pass temporaries/literals directly to functions use a constant reference or pass by value.

Share this post


Link to post
Share on other sites
Quote:
Original post by Conner McCloud
Quote:
Original post by Kest
Is it safe to ignore this warning?

It is rather rare that you want to ignore any warnings. If they could be ignored, the compiler probably wouldn't bother warning you about them.

CM

As far as I understand it, the functionality itself is safe, isn't it? The object becomes invalid once the function call returns. It's impossible to access it afterwards, because it has no handle.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
As scottdewald pointed out, compiler complains because your code is not const-correct. You pass constant object to a function where non constant object is expected. Natural response from compiler is to create non static copy on the stack(so code works) a issue warning because of this.

MaR

Share this post


Link to post
Share on other sites
And a boat-load of information on cost-correctness:

http://www.gotw.ca/publications/advice98.htm

http://www.parashift.com/c++-faq-lite/const-correctness.html

http://www.possibility.com/Cpp/const.html

http://www.linuxjournal.com/article/7629

http://www.cprogramming.com/tutorial/const_correctness.html

Share this post


Link to post
Share on other sites
Quote:
Original post by nobodynews
And a boat-load of information on cost-correctness:

http://www.gotw.ca/publications/advice98.htm

http://www.parashift.com/c++-faq-lite/const-correctness.html

http://www.possibility.com/Cpp/const.html

http://www.linuxjournal.com/article/7629

http://www.cprogramming.com/tutorial/const_correctness.html

The functionality of the object would be impossible in a const state with my situation. The plug object can read from buffers in memory, files, and other locations. It needs to record a read-offset in the memory-source cases.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kest
I just cranked my compiler up from level 3 to level 4 warnings, and there's a lot of work here. One of the warnings pertain to something that I've really relied on:

warning C4239: nonstandard extension used : 'argument' : conversion from 'Class' to 'Class &'.


This is indeed a non-standard extension - by the standard, writing the code this way (without const-correctness) is an *error*. Strange that you'd only get a warning at level 4 for that. :
The philosophy is that if you create a temporary, then you are saying you don't care about it - and don't have a way to check any changes to the object - which is mutually incompatible with the idea of passing it to a function that is expected to create such changes. If the function *does* modify the value, you can always set aside a variable for it separately. Sometimes it helps to make an anonymous scope for the "temporaries" plus the call. But otherwise, FFS be const-correct :)

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
The philosophy is that if you create a temporary, then you are saying you don't care about it - and don't have a way to check any changes to the object - which is mutually incompatible with the idea of passing it to a function that is expected to create such changes.

The plug object was specifically made for that purpose. It translates different types of data so that the loading code doesn't need to worry about where it's coming from. It's literally made to be declared as a temporary to be sent to 'load' functions. It needs to modify it's own data to handle the memory reading, so passing as const won't cut it. Are there any functional differences between declaring the temporary as a parameter as opposed to declaring it before the function call?

void Function(Object &obj, int yep, int nope);
...
{ return Function( Object(1), 2, 3 ); }
{ Object obj(1); return Function( obj, 2, 3); }


Quote:
If the function *does* modify the value, you can always set aside a variable for it separately.

I'm pretty sure I've misunderstood the meaning behind this statement. Do you mean to send temporary data variables to the object to work with from external sources just to avoid sending the reference as non-const?

Quote:
Sometimes it helps to make an anonymous scope for the "temporaries" plus the call. But otherwise, FFS be const-correct :)

I'm not sure I follow you. FFS, hacking code to warp objects into working as const isn't going to solve any of my problems :)

Share this post


Link to post
Share on other sites
Quote:

Quote:
If the function *does* modify the value, you can always set aside a variable for it separately.



I'm pretty sure I've misunderstood the meaning behind this statement. Do you mean to send temporary data variables to the object to work with from external sources just to avoid sending the reference as non-const?

Quote:
Sometimes it helps to make an anonymous scope for the "temporaries" plus the call. But otherwise, FFS be const-correct :)



I'm not sure I follow you. FFS, hacking code to warp objects into working as const isn't going to solve any of my problems :)


what i think zahlman means is whenever you want to call the function to this


{
// some code

// then you want to call it here so you do this
{
SomeClass temp(0, 5, 1); // create the temp
SomeFunction(temp);
}
// now temp doesnt exits here so you arnt poluting this scope with heaps
// of temp variables

// some more code here
}

Share this post


Link to post
Share on other sites
I understand the anonymous scope part of it, but what is the reason? How does that solve any of the problems? The inlined functions which declare the temporary variable already exist. All I had to do was move the construction call out of the parameters and give it a name. I would have done that from the start, I just didn't realize there was any difference between those two situations until I encountered this warning.

The fact that the data isn't destructed right after the call was never a concern for me.

Share this post


Link to post
Share on other sites
Quote:
I understand the anonymous scope part of it, but what is the reason?


There are three main reasons that you would do it.

First the memory being freed which you said you dont care about so ill skip that.

Secondly the variable names if you dont use the anonymous scope and you only want to pass the one class/type like this then you can just have one variable called temp, but suppose you have three different classes that you have to do this with and you need to use all of them in the one scope, you would then need one variable per class in that scope.

And that brings me to the third and MAIN REASON that you would do it, readability, using one variable for the passing of temporaries to mulitple functions could and probaly will confuse ppl who read your code. In contrast using the anonymous scope makes it obvious to anyone reading that the temp variable will ONLY be used to call the function and NOTHING else NOT EVEN other calls to the SAME or a different function.

Quote:
How does that solve any of the problems? The inlined functions which declare the temporary variable already exist. All I had to do was move the construction call out of the parameters and give it a name.


doing explicatly what the copiler was doing for you implicatly will get rid of the warning :-)

Edit: typo

Share this post


Link to post
Share on other sites
Quote:
Original post by Kest
Quote:
Original post by Conner McCloud
Quote:
Original post by Kest
Is it safe to ignore this warning?

It is rather rare that you want to ignore any warnings. If they could be ignored, the compiler probably wouldn't bother warning you about them.

CM

As far as I understand it, the functionality itself is safe, isn't it? The object becomes invalid once the function call returns. It's impossible to access it afterwards, because it has no handle.

In this specific case, yeah, the functionality probably is safe. That's why its just a warning. However, that's not to say it will always be safe. Perhaps tomorrow he will compile on gcc, and gcc performs some optimization that renders all that perfectly safe code into a series of access violations. Or maybe the day after that he does this:

void func(string& str, int& val);

int main()
{
func(string("Hello thar"), 5);
}

The first parameter will compile cleanly, but the second one will spit out an error. The exact same error that the first parameter is supposed to raise. That is, at best, a head scratcher.

*edit: I just realized "he" and "you" are the same person. Oops.

CM

Share this post


Link to post
Share on other sites
There's a perfectly reasonable solution to all this that doesn't require elaborate scoping: don't use a reference in the first place. Pass by value, so that you get a "plug" that you can modify at will. Your internal functions can accept non-const references if you want, because you won't be passing around a temporary any more.

CM

Share this post


Link to post
Share on other sites
Quote:
Original post by Conner McCloud
There's a perfectly reasonable solution to all this that doesn't require elaborate scoping: don't use a reference in the first place. Pass by value, so that you get a "plug" that you can modify at will.

I can't create a copy. The object will open and close files on construction and destruction when in file mode. The object is used to load game state data in. A copy would need to be created every time the object is passed between game hierarchy objects. The only way to avoid that would be to code complicated reference counts or "I know I'm a copy" recognition.

I call Region->Load( Plug( filename ) ); to load a normal game
Region calls Maps->Load( plug ); and Load( plug ) for any other internal data
Map calls Objects->Load ( plug ); for all of it's objects
Objects call Data->Load( plug ); for whatever they need to load

The plug keeps offsets and internal data pointers during this whole trip. With that, I'm able to save and load a complicated hierarchy of objects with little effort. And the data can be written/loaded to memory, file, compressed datafile, or whatever else I add to the plug object later.

The only way for it to stay functional is to declare it before the function call and send it as a non-const reference. Seems like a perfectly valid solution to me.

Quote:
Your internal functions can accept non-const references if you want, because you won't be passing around a temporary any more.

I know it's probably obvious by now, but I wasn't passing by non-const just because I want. That's the only way the system can work. [smile]

Share this post


Link to post
Share on other sites

This topic is 4075 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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