• Create Account

## This error has me perplexed.

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

32 replies to this topic

### #21Cornstalks  Members

Posted 04 April 2013 - 04:56 PM

Is not the reference valid for the lifetime of the temporary object?  I was certain pg.245 of N3337 implies that the temporary object the reference was bound to will exist for the duration of the function, in particular 12.2.5.  Am I reading this wrong?

It's kind of a weird part of C++. The reference/object exists, and it will exist for the duration of the function, but it might not really exist... Confusing? A little. There are two types of existance. The "readonly" type of existence, and the "read+write" type of existence. The object exists (in terms of being able to read it) as far as 12.2.5 is concerned. "existence" doesn't mean you can write to an object. It just means it's there.

I suggest reading this. One of the big reasons for this whole thing is to avoid bugs where temporaries are accidentally modified. (think of it, being able to do 2 = 1; would be weird...)

I also suggest reading this. It might not seem like it makes a lot of sense, and in some ways, it doesn't, but it's just one of those things in C++.

Edited by Cornstalks, 04 April 2013 - 05:03 PM.

[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

### #22Ryan_001  Prime Members

Posted 05 April 2013 - 12:02 AM

I don't think that's what it means.  The idea behind temporaries is that they can be bound to an r-value reference, and that they can be modified.  It'd be kinda useless to have a r-value reference to say a string if I couldn't pilfer the data by swapping the internal pointer (which implies both reading and writing to it).  If I could only read and not write the pointer then the data would be delete'd right away, which wouldn't really make sense.  There's no where I see it stated that temporaries bound to non-const lvalues cannot be modified while temporaries bound to non-const rvalues can be.  Also in your example (2 = 1), neither would bind to a non-const lvalue.  Also the standard does clearly state the temporary will live till the end of the expression (at the very least), which would include the function call.

Far more baffling though is why isn't the VS2012 compiler linking in the proper template function instantiations, and if I've made a mistake in the compiler or linker settings why didn't it tell me instead of just blowing up...

### #23Cornstalks  Members

Posted 05 April 2013 - 07:12 AM

I don't think that's what it means.  The idea behind temporaries is that they can be bound to an r-value reference, and that they can be modified.  It'd be kinda useless to have a r-value reference to say a string if I couldn't pilfer the data by swapping the internal pointer (which implies both reading and writing to it).  If I could only read and not write the pointer then the data would be delete'd right away, which wouldn't really make sense.  There's no where I see it stated that temporaries bound to non-const lvalues cannot be modified while temporaries bound to non-const rvalues can be.  Also in your example (2 = 1), neither would bind to a non-const lvalue.  Also the standard does clearly state the temporary will live till the end of the expression (at the very least), which would include the function call.

The thing is, you're not supposed to be able to take an l-value reference to an r-value. Yes, there are some ways that an r-value reference may be modified (through calling non-const member functions, or if you're using move semantics), but they're not supposed to be modified through any other means.

But it's possible Visual Studio allows it. I just know that in standard C++, it's illegal.

Far more baffling though is why isn't the VS2012 compiler linking in the proper template function instantiations, and if I've made a mistake in the compiler or linker settings why didn't it tell me instead of just blowing up...

Are you sure that's the error? The error you're describing sounds a whole lot like you're invoking undefined behavior somewhere. Are you linking to two different versions of the standard library? If you're not, then I highly doubt that is your problem, and would expect your problem to be undefined behavior being invoked elsewhere. Seriously though, at least try passing in a variable to throw_detailed() instead of a temporary.

Also, I suggest you post the *full* code, because that's not it. You're not showing what Exception::GetLineNumber() is, for example.

Somewhere you're invoking undefined behavior. I'd be shocked if the template instantiation is the problem (unless you're linking to different versions of the standard library).

[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

### #24Ryan_001  Prime Members

Posted 05 April 2013 - 08:50 AM

The function Exception::GetLineNumber() is:

std::string Exception::GetLineNumber () const {
const int* line = boost::get_error_info<boost::throw_line>(*this);
if (line) {
std::stringstream ss;
ss << *line;
return ss.str();
}
return "unknown line";
}


BTW I did change throw_detailed to:

template <typename T> BOOST_ATTRIBUTE_NORETURN void ThrowException (T e, const char* func, const char* file, int line) {


and Exception constructor looks like:

Exception::Exception (const std::string& msg) {
*this << ErrMsgInfo(msg);
}

And that's all.

Edited by Ryan_001, 05 April 2013 - 08:51 AM.

### #25jms bc  Members

Posted 05 April 2013 - 08:52 AM

Far more baffling though is why isn't the VS2012 compiler linking in the proper template function instantiations, and if I've made a mistake in the compiler or linker settings why didn't it tell me instead of just blowing up...

I have a vague recollection of accomplishing this through haphazard includes spread out unnecessarily. Also, something to do with using different versions of Visual Studio (I've usually had several version installed on the same machine). Sorry about the brain damage here...please post the solution when you find it.

The Four Horsemen of Happiness have left.

### #26Ryan_001  Prime Members

Posted 05 April 2013 - 09:01 AM

The thing is, you're not supposed to be able to take an l-value reference to an r-value. Yes, there are some ways that an r-value reference may be modified (through calling non-const member functions, or if you're using move semantics), but they're not supposed to be modified through any other means.

But it's possible Visual Studio allows it. I just know that in standard C++, it's illegal.

But you bind rvalues to lvalue references all the time.  For example:

string s("hello");
cout << s.find(string("l") + string("o")) << endl;


This may be a contrived example, but temporary values are constantly bound to lvalue references.

Edited by Ryan_001, 05 April 2013 - 09:02 AM.

### #27Ryan_001  Prime Members

Posted 05 April 2013 - 09:26 AM

I found it, a silly oversight on my part (as usual).

I compiled the library with the /vmg compiler option, and I didn't do the same with the program, I had forgotten it.

Thank-you very much for your time and insight.  I know I checked my compiler and linker options repeatedly, I'm not sure how I had missed that.

### #28SiCrane  Moderators

Posted 05 April 2013 - 09:31 AM

This may be a contrived example, but temporary values are constantly bound to lvalue references.

The rule is that temporaries can't (normally) be bound to non-const lvalue references. Binding a temporary to a const lvalue reference is perfectly fine. Binding a temporary to a non-const lvalue reference can be done, but requires trickery or a compiler extension like MSVC has.

### #29Cornstalks  Members

Posted 05 April 2013 - 09:57 AM

The thing is, you're not supposed to be able to take an l-value reference to an r-value. Yes, there are some ways that an r-value reference may be modified (through calling non-const member functions, or if you're using move semantics), but they're not supposed to be modified through any other means.

But it's possible Visual Studio allows it. I just know that in standard C++, it's illegal.

But you bind rvalues to lvalue references all the time.  For example:

string s("hello");
cout << s.find(string("l") + string("o")) << endl;


This may be a contrived example, but temporary values are constantly bound to lvalue references.

Sorry, poor wording on my part. I meant non-const lvalue reference (i.e. the kind of reference we've been talking about in the code).

Edited by Cornstalks, 05 April 2013 - 09:58 AM.

[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

### #30Ryan_001  Prime Members

Posted 05 April 2013 - 10:31 AM

Well even if it wasn't the problem its good to know Corn/SiCrane.  Its something I will not do, despite not making much sense IMHO.

### #31Cornstalks  Members

Posted 05 April 2013 - 10:45 AM

Well even if it wasn't the problem its good to know Corn/SiCrane.  Its something I will not do, despite not making much sense IMHO.

Yeah, it's kind of weird. I think it kind of makes sense (helping you not assign to temporaries that are about to get nuked can help avoid some bugs), but at the same time, it seems like an unnecessary restriction. I think that's the main reason this question has so many upvotes, but answers don't (that is, the question is a good, interesting question, but the answers (provided by the standard) aren't very satisfactory).

I think the best answer to this question is actually in one of the comments in that question (from sbi):

The reason Stroustrup gives (in [Design and Evolution of C++]) for disallowing the binding of rvalues to non-const references is that, if Alexey's g() would modify the object (which you'd expect from a function taking a non-const reference), it would modify an object that's going to die, so nobody could get at the modified value anyway. He says that this, most likely, is an error.

It seems kinda weird that C++ is trying to hold your hand here (seeing that the rest of the standard doesn't care if you shoot your leg off if you want), but oh well.

[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

### #32Ectara  Members

Posted 05 April 2013 - 03:42 PM

### #33iMalc  Members

Posted 06 April 2013 - 05:03 PM

The problem isn't throwing the object. The problem is modifying the temporary object, which (by standard C++) is undefined behavior. The problem is binding a non-constant reference to a temporary object and then modifying the object (not throwing the object). In the ThrowException() function, e is a reference to a temporary, and you are modifying it, which is undefined behavior. e should be a const reference, and you should not modify it (feel free to throw it).

Is not the reference valid for the lifetime of the temporary object?  I was certain pg.245 of N3337 implies that the temporary object the reference was bound to will exist for the duration of the function, in particular 12.2.5.  Am I reading this wrong?
Nope, it's not. A const-reference extends the lifetime of a temporary object, a non-const-reference does not.
See GotW #88:
http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/

Edited by iMalc, 06 April 2013 - 05:03 PM.

"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.