Unforgiving GCC C++ compiler - c++

MS VS x86 compiler has no problem with the following definitions, but GCC (ARM) complains. Is GCC dumb or is MSVS_x86 too clever?
bool checkPointInside(const CIwVec2& globalPoint) {
return checkPointIn(globalPoint, CIwVec2());
}; /// error: no matching function for call to 'Fair::Sprite::checkPointIn(const CIwVec2&, CIwVec2)'
bool checkPointIn(const CIwVec2& globalPoint, CIwVec2& localPoint) {
return false;
};

According to the C++ standard, you cannot bind an rvalue to a non-const reference. The Microsoft compiler has an evil extension that allows this, however. So g++ is correct not to accept your program.

g++ is right to complain and Microsoft has this wrong. The problem with this code is that the checkPointIn function takes it's second parameter by reference, meaning that it must take an lvalue (a variable, or a dereferenced pointer, for example). However, the code in checkPointInside is passing in a temporary object, which is an rvalue. For historical reasons the Microsoft compiler allows this, though it's explicitly forbidden by the spec. Usually, if you crank the warning level all the way up in the Microsoft compiler, it will indeed flag this code as erroneous.
To fix this, either have checkPointIn take its last argument by value or by const reference. The latter is probably the better choice, since const references can bind to rvalues if necessary and avoid making costly copies in other cases.

You can't create references to temporaries (only constant references or r-value references in C++0x).
This is happening when you call checkPoint with CIwVec2() as second parameter.

Related

linux error when passing strings to functions c++

I am making a c++ program and I am stuck on the stage of hosting it on linux. (in fact it is an addon for node.js, but it does not matter now). I get an error when compiling my function on linux (on windows everything is OK).
error: cannot bind non-const lvalue reference of type ‘std::__cxx11::string&’ {aka ‘std::__cxx11::basic_string<char>&’} to an rvalue of type ‘std::__cxx11::string’ {aka ‘std::__cxx11::basic_string<char>’}
return(merge(messUp3(a.substr(0, (int)(a.size()) / 2)), messUp3(a.substr((int)(a.size()) / 2))));
the problem is exactly here: a.substr(0, (int)(a.size()) / 2). I have managed to fix the error by deleting & from arguments of functions. string merge(string& a, string& b) -> string merge(string a, string b). I think I have some understanding, why it should not work with &, but then I get a complete misunderstanding of why does it work on windows? How do linux and windows gcc compilers differ? Or the problem is somewhere else?
A reference like std::string & references a value that already exists as an identifiable object in memory (for example by its memory address), which is called an lvalue in C++ terminology.
The return value of a function is a temporary value that has not identity. The compiler is not required to allocate an address for it, which is called an rvalue in C++ terminology.
Thus, you cannot assign an rvalue to an lvalue reference, as the error message says.
(In fact these so-called value categories are a bit more complicated in C++.)
If you replace std::string & by std::string you create a new variable and copy the rvalue into it instead of referencing it, which is ok, because in this case you only read the rvalue instead of referencing it. (To be precise the rvalue will be moved but explaining that is beyond the scope of this answer.)
Your Windows compiler is obviously less strict with the C++ standard by creating a workaround internally instead of pointing out the error. Maybe that compiler has an option to make it more standard-conforming. I'd recommend to turn on such option, particularly if you develop for different platforms, but also to create more clean code.

Binding r-value to l-value reference is non-standard Microsoft C++ extension

I've been working on a project recently, and I decided to install ReSharper C++ to Visual Studio. When it analysed my code it spat out a bunch of new warnings (apparently I have bad coding habits..). One of them that took me a while to figure out was Binding r-value to l-value reference is non-standard Microsoft C++ extension. I've recreated the warning with the following code:
Type foo(Type t1, Type t2) {
return Type(t1.value & t2.value);
}
The expression t1.value & t2.value triggers the warning. I understand the second part of the warning, which means that my code only compiles due to a Microsoft extension, and other compilers would refuse to compile it. I'm using an overloaded operator, which returns an object (called Datum) which Type takes as a constructor parameter, as a reference (Type::Type(Datum& dat)).
With some playing around, I managed to make the warning go away by refactoring the code:
Type bar(Type t1, Type t2) {
Datum datum = t1.value & t2.value;
return Type(datum);
}
To my understanding, this is functionally equivalent to the code that generated the warning. What I'd really like to know is whether there's something here that I should be aware of, because I'm pretty confused about why one function complains and one doesn't.
I think I've got it figured out. I already had the question typed out, so I'm going to post it with what I found, for the reference of others. I don't really have enough knowledge to go into detail, so please feel free to expand on or correct my answer if it isn't satisfactory :)
That's one way to remove the warning: the variable is an lvalue, so can bind directly to the dodgy constructor's reference parameter, while the expression result is an rvalue which can't.
A better solution is to fix the constructor to take its argument by value or constant reference:
Type(Datum dat) // value
Type(Datum const & dat) // constant reference
Now you can give the argument as either an lvalue or an rvalue.
From what I can see, the reason I got such behaviour is because the Type constructor is taking a reference to the Datum object, rather than passing it by value. This causes a warning in Type foo(Type, Type) because the compiler doesn't like taking the reference of expressions, which would be due to the semantics of expression evaluation.
Again, please feel free to elaborate on or correct my findings, as this is simply the result of my experimentation and inference.

Make a function returning temporary object inline?

I'm writing an iterator for a new container in c++. When I call begin() and end() functions (both very short), I expected the compiler to make it inline. But it didn't. I think maybe it's because the iterator is returned as a temporary object, and it needs to be copied. I think maybe I can use the RValue reference in c++11, but I'm not familiar with it. So is there a way to make it inline?
The code is something like this (not exactly the same, but I think if this version works, my code will also work)。
I'm using VC++ 2013 CTP, and I have changed compile options but it doesn't work either.
class Pointer
{
public:
Pointer(int* p) : p(p)
{
(*p)++;
}
Pointer(const Pointer& pointer) : p(pointer.p)
{
(*p)++;
}
Pointer& operator =(const Pointer& pointer)
{
(*p)--;
p = pointer.p;
(*p)++;
}
int* p;
~Pointer()
{
(*p)--;
}
static Pointer create(int& p)
{
return Pointer(&p);
}
static Pointer create2(int& p)
{
return create(p);
}
};
int main()
{
int p = 0;
Pointer pointer = Pointer::create2(p);
}
The function create and create2 here are not inline even if, you can see, it's really simple.
I know maybe this doesn't make a difference in the speed of my program, but I just want to have it better.
There are several cases where microsoft's compiler cannot inline functions:
http://msdn.microsoft.com/en-us/library/a98sb923.aspx
In some cases, the compiler will not inline a particular function for mechanical reasons. For example, the compiler will not inline:
A function if it would result in mixing both SEH and C++ EH.
Some functions with copy constructed objects passed by value when -GX/EHs/EHa is on.
Functions returning an unwindable object by value when -GX/EHs/EHa is on.
Functions with inline assembly when compiling without -Og/Ox/O1/O2.
Functions with a variable argument list.
A function with a try (C++ exception handling) statement.
Because the functions return Pointer by value and it has a destructor, the functions cannot be inlined.
There's nothing that can really be done about it other than changing the Pointer class. Rvalue refs don't help here. I would just leave the code as it is and if you need better performance in final product, try another compiler.
RVO may happen here but it doesn't make difference because the cost of copying is so small.
In the C languages there is simply no way to force inlining. inline is just a hint to the compiler to perform inlining, but it is not required to do so.
The only way to "force inline" would be to use preprocessor macros, but that's easy to get wrong. Wrong in that the macro doesn't do what you expect, and wrong in that the macro actually produces slower code. Also, preprocessor macros are no substitute for member functions.
So, if the compiler doesn't want to inline, there's not much you can do about it, and nothing you should do about it.
The answer by Timo is correct for any combination of the /EH?? flag (and /EH?? must be specified to allow any useful exception handling), specifically, MSVC Studio-2015 as well as Studio-2017 15.1 and 15.2 versions will not ever inline a function call if a D'tor is present.
However, I recently found a UserVoice Issue -- Support inlining for functions returning unwindable objects -- for this: (Dec', 2016)
Within deeply-templated codes, it seems quite common to call a
function which simply forwards the arguments into another function,
which again just forwards the arguments into another function, which
again just do forwarding, and so on. As I know, current version of
Visual C++ is not able to inline such a function if it returns an
object with non-trivial destructor, whenever exceptions are enabled.
This often makes a performance hit particularly when the level of
forwarding is unavoidably deep and there are many arguments with
not-so-small sizes. I very much hoped if the upcoming Visual C++ 2017
has solved this problem, but it seems not.
And a comment that states it will be fixed in VS2017 v15 .3 and links to a connect issue where a comment states:
The inlining limitation was because of the presence of exception handling. We have recently improved our inliner and it can now inline std::make_unique in the case you provided. Please download the latest VS 2017 version to try it out. Note that in VS 2017 RTM, this new inlining is off by default, but you can turn it on by adding the flags /d1ReturnUdtEHInline /d2ReturnUdtEHInline to cl.exe. It will be on by default in a future release.
Note that /d1 and /d2 switches are undocumented switches for the front/backend of the compiler.
and
You should expect it to be on by default in the VS 2017 15.3 release.
So, maybe there's hope this will be actually fixed in VS2017 U3.
Two short Godbolt examples to experiment with:
https://godbolt.org/g/1y9UpE
https://godbolt.org/g/3mAzGe

Invalid use of rvalue references from old code: how should I update it to modern, correct usage?

I am porting a large project from C++ Builder 2010 to XE4, and have just come across this code. It compiled, ran, and apparently worked in CB2010, and according to the revision log was added when we were still using C++ Builder 2007. Neither of these compilers supported rvalue references.
VOperandValue& VOperandValue::operator=(VOperandValue&& oOther) {
// Assignment operator takes full control of all pointers etc, and sets oOther
// to not own anything
if (static_cast<void*>(this) != static_cast<void*>(&oOther)) {
CopyAndTakeOwnershipFrom(oOther);
}
return *this;
}
void VOperandValue::CopyAndTakeOwnershipFrom(VOperandValue&& oOther) {
// Lots of assignments to self's members, and clearing fields of oOther
}
Two things to note:
operator= changing the copied-from object is deliberate. This class wraps resources that can only be owned by one object at a time. It's beyond the scope of this question, but the behaviour, while odd, is as designed. There is also a copy constructor and a few others methods that have been changed similarly. The methods are intended for use where the copied-from objects are either about to become invalid (eg destroyed) or will be re-used to hold something new. I have no idea why static_cast<void*> is necessary for comparing the pointers to objects of the same type; it seems a very odd thing to do, to me.
The code was changed from using standard references (ie VOperandValue& oOther) to rvalue-references. Despite support for rvalue references only being added in C++Builder XE, the version after C++Builder 2010, the compiler happily accepted and compiled it, and the code appears to have worked when run.
Now this code is loaded into XE4, it fails to compile on the line CopyAndTakeOwnershipFrom(oOther) with the following errors:
[bcc32 Error] OperandValue.cpp(178): E2559 Can't initialize rvalue
reference of type 'VOperandValue' with lvalue of type 'VOperandValue'
[bcc32 Error] OperandValue.cpp(178): E2342 Type mismatch in parameter
'oOther' (wanted 'VOperandValue &&', got 'VOperandValue')
(I don't understand these errors, since line 178 is the line CopyAndTakeOwnershipFrom(oOther);, and oOther appears to definitely have been defined in the method parameter list as an rvalue-reference. Why then is it having trouble with an lvalue non-r-ref when passing the same variable?)
I have two questions, a primary practical question and a secondary curiosity question:
Primary: The coder who changed this code from using standard references to rvalue-references presumably did so thinking that move semantics were best in this situation. I can understand that, though assignment involves copying pointer values only, which isn't much work. How would I, if they're suitable, correctly use rvalue-references for this code?
Secondary: (Curiosity only.) What did the 2007 and 2010 compilers make of this code? Was it read as a reference to a reference? Did the two & operators coalesce and become a single reference? Since it was, presumably, invalid syntax, yet it compiled and worked fine, what on earth was it doing?
As a solution to your problem you can use std::forward.
Just change your code to:
#include <utility>
CopyAndTakeOwnershipFrom(std::forward<VOperandValue>(oOther));
The problem arises because you want to forward move semantics through 2 functions but in the first function the moved object gets a name. With a name its not an rvalue anymore without std::forward but an lvalue that cannot be used for a T&& parameter in CopyAndTakeOwnershipFrom.
That it worked before in C++ Builder 2010 seems to be a bug there which got fixed in XE4.

Taking the address of a temporary object

§5.3.1 Unary operators, Section 3
The result of the unary & operator is a pointer to its operand. The operand shall be an lvalue or a qualified-id.
What exactly does "shall be" mean in this context? Does it mean it's an error to take the address of a temporary? I was just wondering, because g++ only gives me a warning, whereas comeau refuses to compile the following program:
#include <string>
int main()
{
&std::string("test");
}
g++ warning: taking address of temporary
comeau error: expression must be an lvalue or a function designator
Does anyone have a Microsoft compiler or other compilers and can test this program, please?
The word "shall" in the standard language means a strict requirement. So, yes, your code is ill-formed (it is an error) because it attempts to apply address-of operator to a non-lvalue.
However, the problem here is not an attempt of taking address of a temporary. The problem is, again, taking address of a non-lvalue. Temporary object can be lvalue or non-lvalue depending on the expression that produces that temporary or provides access to that temporary. In your case you have std::string("test") - a functional style cast to a non-reference type, which by definition produces a non-lvalue. Hence the error.
If you wished to take address of a temporary object, you could have worked around the restriction by doing this, for example
const std::string &r = std::string("test");
&r; // this expression produces address of a temporary
whith the resultant pointer remaining valid as long as the temporary exists. There are other ways to legally obtain address of a temporary object. It is just that your specific method happens to be illegal.
When the word "shall" is used in the C++ Standard, it means "must on pain of death" - if an implementation does not obey this, it is faulty.
It is permitted in MSVC with the deprecated /Ze (extensions enabled) option. It was allowed in previous versions of MSVC. It generates a diagnostic with all warnings enabled:
warning C4238: nonstandard extension used : class rvalue used as lvalue.
Unless the /Za option is used (enforce ANSI compatibility), then:
error C2102: '&' requires l-value
&std::string("test"); is asking for the address of the return value of the function call (we'll ignore as irrelevant the fact that this function is a ctor). It didn't have an address until you assign it to something. Hence it's an error.
The C++ standard is a actually a requirement on conformant C++ implementations. At places it is written to distinguish between code that conformant implementations must accept and code for which conformant implementations must give a diagnostic.
So, in this particular case, a conformant compiler must give a diagnostic if the address of an rvalue is taken. Both compilers do, so they are conformant in this respect.
The standard does not forbid the generation of an executable if a certain input causes a diagnostic, i.e. warnings are valid diagnostics.
I'm not a standards expert, but it certainly sounds like an error to me. g++ very often only gives a warning for things that are really errors.
user defined conversion
struct String {
std::string str;
operator std::string*() {
return &str;
}
};
std::string *my_str = String{"abc"};