Need some help about "swap" function in c++ - c++

I am new to C++ programming. I am trying to compile another person's program, and the software reported a bug that I don't know how to solve (the software I use is Visual Studio 2019).
The line of code with bug is:
swap(allBeamPoints, unordered_map<int, vector<LidarPoint>>());
The definition for variable allBeamPoints is:
unordered_map<int, vector<LidarPoint>>allBeamPoints
The error information is:
Error C2665 'std::swap': none of the 2 overloads could convert all the argument types
and
Error (active) E0304 no instance of overloaded function "swap" matches the argument list
However, if I type the following codes, no bug will be reported:
unordered_map<int, vector<LidarPoint>> allBeamPoints_new;
swap(allBeamPoints, allBeamPoints_new);
Does anyone know what the problem is? Did I fail to link some of the required libraries? How should I check those libraries?

The older MSVC compilers allowed the binding of an anonymous temporary to a non-const reference function parameter. That's not standard C++.
So
swap(allBeamPoints, unordered_map<int, vector<LidarPoint>>());
which had the effect of clearing allBeamPoints was reasonably idiomatic in code that only targeted Microsoft platforms.
It's wrong and not portable as you now observe. Use
allBeamPoints.clear();
instead to clear the map. Your second snippet compiles since allBeamPoints_new is not an anonymous temporary.

Related

Issue porting OpenExr (3rd party of OpenCV) to C++ Builder 32-bit compiler

I'm trying to port OpenCV to C++ Builder (XE3 version).
I've encountered many compiler errors.
As I know, BCC 32-bit is not a clang complaint compiler, and does not follow C++11 standards. This is why I have met with so many issues.
I tried to resolve parts of these issues one by one with workarounds. However, I cannot resolve the following one. Can someone help me about this?
p.s. I know it is an issue with BCC32, as this code can be compiled successfully with Visual Studio, or even BCC64 compiler.
The following code is extracted from ImfBoxAttribute.cpp (in opencv 2.4.11\sources\3rdparty\openexr\IlmImf)
template <>
void
Box2iAttribute::writeValueTo (OStream &os, int) const
{
Xdr::write <StreamIO> (os, _value.min.x);
Xdr::write <StreamIO> (os, _value.min.y);
Xdr::write <StreamIO> (os, _value.max.x);
Xdr::write <StreamIO> (os, _value.max.y);
}
When I compile with C++ Builder XE3 32bit, I meet with the following compiler errors:
[bcc32 Error] ImfBoxAttribute.cpp(61): E2171 Body has already been defined for function 'Box2iAttribute::writeValueTo(OStream &,int) const'
and
[bcc32 Error] ImfBoxAttribute.cpp(62): E2451 Undefined symbol 'os'
Full parser context
ImfBoxAttribute.cpp(47): namespace Imf
ImfBoxAttribute.cpp(61): parsing: void Box2iAttribute::writeValueTo(OStream &,int) const
Here is the definition of Box2iAttribute:
typedef TypedAttribute<Imath::Box2i> Box2iAttribute;
typedef Box <V2i> Box2i;
I don't see how this is valid code, in any pre-C++11 compiler. You are trying to define a template specialized implementation for Box2iAttribute::writeValueTo(), but Box2iAttribute is just an alias for TypedAttribute<Imath::Box2i> and cannot be used to qualify an implementation like you are attempting. And where is the template parameter that you are trying to specialize? It is not attached to Box2iAttribute, it would have to be attached to writeValueTo() instead. But where is the specialization actually declared? And the fact that the compiler is complaining about an existing body means that a TypedAttribute<Imath::Box2i>::writeValueTo() implementation has already been defined, so you cannot define a new one.
Maybe C++11 allows this weird code, which would explain VS and BCC64 accepting it. But you are certainly not going to get BCC32 to accept it. If you want help porting this code to BCC32, or any other pre-C++11 compiler, you need to show a more complete example demonstrating exactly what you are trying to accomplish. What you have shown is not complete. Please don't ask people to go download external libraries just to see the code. Post the relevant pieces here, or create a MCVE demonstrating the same concepts.

Visual Studio 2012 compiler alternative on Linux?

I switched to Linux a few days ago and I'm stuck on porting my project. For some reason, no matter if I'm using clang++ or gcc 4.8, the compiler complaints about using a atomic with a vector from the GLM-Library (something like that: atomic<glm::vec3>). I tried to set -std=c++11 and -std=gnu++11, which gcc doesn't accept and g++/clang++ don't care about. I know that it's not my code, because it worked on Windows with Visual Studio 2012.
So now my question is, if there is a good alternative to the VS2012 compiler, so that my code gets to work? I also thought to try gcc 4.9, but I really have no idea how to get that.
clang error message:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/atomic|166|error: exception specification of explicitly defaulted default constructor does not match the calculated one|
g++ error message:
/usr/include/c++/4.8/atomic|167|error: function ‘std::atomic<_Tp>::atomic() [with _Tp = glm::detail::tvec3<float>]’ defaulted on its first declaration with an exception-specification that differs from the implicit declaration ‘std::atomic<glm::detail::tvec3<float> >::atomic()’|
glm::vec3 is a typedef to some specialization of tvec<float, T>. tvec has a user-provided assignment operator, so it is not trivially copyable and therefore cannot be used with std::atomic. The code compiles with VS2012 because Microsoft's standard library implementation doesn't diagnose instantiations of std::atomic<T> for non-TriviallyCopyable T. As with any undefined behavior, the fact that it compiles does not imply that it works.
std::atomic<glm::vec3> // sizeof(...) == 12
This specialization does not exist. There are only specialization of bool, integral types and pointer types provided by the STL. Either you have to specialize it on your own, or have to use another solution for your specific problem. Please note, that std::atomic<glm::vec3> may not be TriviallyCopyable on your platform (because of the size it may nowhere be trivially copyable). This means, that a mutex is used to synchronize this. For a vector I am really sure, that there is no way to trivially copy it. So you may use a pair of vector and mutex instead.

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.

boost::bind doesn't work in VC++ 2010 when binding a function that throws exceptions

I have some code which compiles fine under Linux, but I am trying to port it to Windows. I have used the Boost 1.50 precompiled binaries from Boost Pro, but when I compile my code I get this cryptic error:
error C2664: 'boost::_bi::bind_t<R,F,L>::bind_t(const boost::_bi::bind_t<R,F,L> &)' :
cannot convert parameter 1 from 'boost::_bi::bind_t<R,F,L>'
to 'const boost::_bi::bind_t<R,F,L> &'
C:\Program Files (x86)\boost\boost_1_50\boost\bind\bind_cc.hpp [line] 50
The error is most unhelpful because it shows up deep in the Boost header files, with no indication of where in my code the problem is. Nevertheless by commenting out various blocks of code I have narrowed it down to this as the cause:
void test(int a)
throw (int) // removing this line makes it compile
{
return;
}
...
boost::function<void(int)> fn = boost::bind<void>(test, _1);
It works if I remove the throw specifier in the function definition. It doesn't matter what I throw, whether it's a class or just an int. Am I doing something wrong, or can't you bind to functions that throw exceptions in Visual C++? The Boost Bind docs don't seem to suggest any issues with this, and GCC doesn't have a problem with it either way.
[Side note: The code above is not my actual code, but when compiled it exhibits the same problem. Please avoid comments about throwing ints being bad and the like, as this is only supposed to be a trivial example in case anyone wishes to reproduce the problem.]
I don't know why your code fails on VC++. However, in general exception specifications are best avoided because they can introduce very subtle effects. See this excellent column A Pragmatic Look at Exception Specifications by Herb Sutter:
So here’s what seems to be the best advice we as a community have
learned as of today:
Moral #1: Never write an exception specification.
Moral #2: Except possibly an empty one, but if I were you I’d avoid
even that.

Porting c++ code from unix to windows

Hi i have to port some stuff written on c++ from unix bases os to windows visual studio 2008.
The following code implements array data type with void ** - pointer to the data.
struct array
{
int id;
void **array; // store the actual data of the array
// more members
}
When i compile with g++ on Unix it's ok but when i try with MSVS 2008 I get the error - error C2461: 'array' : constructor syntax missing formal parameters. When i change the member from 'array' to something else it works, so it seems that the compiler thinks that the member name 'array' is actually the constructor of the struct array. It's obviously not a good practice to name the member like the struct but it's already written that way. Can i tell the MSVS compiler to ignore this problem or i should rename all members that are the same as the struct name.
You are dealing with a bug in GCC compiler. C++ language explicitly prohibits having data members whose name is the same as the name of the class (see 9.2/13). MS compiler is right to complain about it. Moreover, any C++ compiler is required to issue a diagnostic message in this case. Since GCC is silent even in '-ansi -pedantic -Wall' mode, it is a clear bug in GCC.
Revison: What I said above is only correct within the "classic" C++98 specification of C++ language. In the most recent specification this requirement only applies to static data members of the class. Non-static data members can now share the name with the class. I don't know whether this change is already in the official version of the revised standard though.
That means that both compilers are correct in their own way. MS compiler sticks to the "classic" C++98 specification of the language, while GCC seems to implement a more recent one.
I'd say that if you're doing something that you yourself describe as "not a good practice", then you should change it.
I would rename your attribute to not have the same name as the class. This will make your code more portable. If you have to move to yet another compiler in the future, you won't run in to this problem again then.