Cannot use unique_ptr inside a map in a vector? - c++11

I would like to use unique_ptr inside map in vector. But I got an error message.
I am not sure why and how to solve this problem.
This is the code.
#include <memory>
int main(int argc, char** argv)
{
std::vector<std::map<int, std::unique_ptr<std::string>>> outputContainers;
std::map<int, std::unique_ptr<std::string>> outputContainer;
outputContainer[0] = std::make_unique<std::string>("test");
outputContainers.push_back(std::move(outputContainer));
}
This is an error message.
Error C2280 'std::pair<const int,std::unique_ptr<std::string,std::default_delete<std::string>>>::pair(const std::pair<const int,std::unique_ptr<std::string,std::default_delete<std::string>>> &)': attempting to reference a deleted function test C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.24.28314\include\xmemory 671

When a vector needs to reallocate, it may move elements to the new storage if the element's type is_nothrow_move_constructible; otherwise, it has to copy (so it can unwind back to the original state if any constructor throws an exception).
std::map's move constructor is not required to be noexcept. Some implementations may provide stronger guarantees than required by the standard, and make it noexcept; others may not.
The interaction of these two facts leads to a vector of maps of move-only type being non-portable - it may compile with some implementations but not others.

Related

using std::max causes a link error?

Consider a library that defines in a header file
struct Proj {
struct Depth {
static constexpr unsigned Width = 10u;
static constexpr unsigned Height = 10u;
};
struct Video {
static constexpr unsigned Width = 10u;
static constexpr unsigned Height = 10u;
};
};
The library gets compiled, and I'm now developing an application that links against this library. I thought for a long time it was some kind of visibility problem, but even after adding B_EXPORT (standard visibility stuff from CMake) everywhere with no change, I finally found the problem.
template <class Projection>
struct SomeApplication {
SomeApplication() {
unsigned height = std::max(// or std::max<unsigned>
Projection::Depth::Height,
Projection::Video::Height
);
}
};
I can't even reproduce the problem with a small dummy library / sample application. But using std::max in the application causes the link error, whereas if I just do it myself
unsigned height = Projection::Depth::Height;
if (height < Projection::Video::Height)
height = Projection::Video::Height;
Everything works out. AKA there don't appear to be any specific issues with the visibility in terms of just using Projection::XXX.
Any thoughts on what could possibly cause this? This is on OSX, so this doesn't even apply.
The problem is that Width and Height are declared, not defined in your structs. Effectively, this means there is no storage allocated for them.
Now recall the signature for std::max:
template<typename T>
const T& max(const T&, const T&);
Note the references: this means the addresses of the arguments are to be taken. But, since Width and Height are only declared, they don't have any storage! Hence the linker error.
Now let's consider the rest of your question.
Your hand-written max works because you never take any pointers or references to the variables.
You might be unable to reproduce this on a toy example because, depending on the optimization level in particular, a sufficiently smart compiler might evaluate max at compile time and save the trouble of taking the addresses at runtime. For instance, compare the disasm for no optimization vs -O2 for gcc 7.2: the evaluation is indeed done at compile-time!
As for the fix, it depends. You have several options, to name a few:
Use constexpr getter functions instead of variables. In this case the values they return will behave more like temporary objects, allowing the addresses to be taken (and the compiler will surely optimize that away). This is the approach I'd suggest in general.
Use namespaces instead of structs. In this case the variables will also be defined in addition to being declared. The caveat is that you might get duplicate symbol errors if they are used in more than one translation unit. The fix for that is only in form of C++17 inline variables.
...speaking of which, C++17 also changes the rules for constexpr static member variables (they become inline by default), so you won't get this error if you just switch to this standard.

How to register OGRLineString as boost linestring?

I would like to use the boost::geometry::simplify method with OGRLineStrings.
While I am able to register the OGRPointvia the macro:
BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET(OGRPoint, double, cs::cartesian, OGRPoint::getX, OGRPoint::getY, OGRPoint::setX, OGRPoint::setY)
I am currently not able to use the following code:
#include <boost/geometry/geometry.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/geometry/geometries/register/linestring.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET(OGRPoint, double, cs::cartesian, OGRPoint::getX, OGRPoint::getY, OGRPoint::setX, OGRPoint::setY)
BOOST_GEOMETRY_REGISTER_LINESTRING(OGRLineString)
void example()
{
OGRLineString test;
OGRLineString simplified;
boost::geometry::simplify(test, simplified, 0.5);
}
The Simplyfy method doens't compile and I get errors stating something about boost:mpl::eval_if_c which doesn't help me.
A Boost.Geometry linestring must fulfil the Boost.Range Concept. A std::vector would, for example, do. But an OGRLineString, out of the box,.
First, there should be an iterator defined, walking over the points the OGRLineString contains. Using OGRLineString::getPoint(...) this should basically be possible.
Second, if the iterator is implemented, which is probably the toughest part, OGRLineString should be adapted to Boost.Range, e.g. as described here.
If that is done, Boost.Geometry should recognize the OGRLineString as a linestring and can read it.
However, to write into an OGRLineString, an additional step should be done. It should be a "mutable range". Because that is not (yet) defined in Boost.Range, it is until now a geometry-only thing and can be implemented by specializing three classes in the boost::geometry::traits namespace (clear, push_back and resize).

maintain MPI version and non MPI version in a convenient way

Recently, I used MPI to parallelize my simulation program to speed up. The way I adopted was to rewrite one function that is very time-consuming but easy to be parallelized.
The simplified model of non-MPI program is as follows,
int main( int argc, char* argv[] ){
// some declaration here
Some_OBJ.Serial_Function_1();
Some_OBJ.Serial_Function_2();
Some_OBJ.Serial_Function_3();
return 0;
}
While my MPI version is,
#include "mpi.h"
int main( int argc, char* argv[] ){
// some declaration here
MPI_Init( NULL, NULL );
Some_OBJ.Serial_Function_1();
Some_OBJ.Parallel_Function_2(); // I rewrite this function to replace Some_OBJ.Serial_Function_2();
Some_OBJ.Serial_Function_3();
MPI_Finalize();
return 0;
}
I copied my non MPI code to a new folder, something like mpi_simulation, and add a mpi function, revised the main file to . It works, but very inconveniently. If I update some functions, say OBJ.Serial_Function_1(), I need to copy the code with caution even if I just change a constant. There are still some slight differences between these versions of programs. I felt exhausted to keep them in accordance.
So I wander if there is any way to let MPI program dependent on non MPI version, so that my revisions can be easily applied to both of them safely and conveniently.
Thanks.
Update
I finally adopt haraldkl's suggestion.
The method is to define a macro to enclose all functions that use MPI interfaces, like this:
#ifdef USE_MPI
void Some_OBJ::Parallel_Function_2(){
// ...
}
#endif
To initialize MPI automatically, I define a singleton called MPI_plugin:
#ifdef USE_MPI
class MPI_plugin{
private:
static MPI_plugin auto_MPI;
MPI_plugin(){
MPI_Init( NULL, NULL );
}
public:
~MPI_plugin(){
MPI_Finalize();
}
};
MPI_plugin::MPI_plugin auto_MPI;
#endif
Including MPI_plugin.h in main.cpp can survive me from adding MPI_Init() and MPI_Finalize() in main.cpp when compiling MPI version.
The last step is to add a PHONY target "mpi" in makefile:
CPP := mpic++
OTHER_FLAGS := -DUSE_MPI
.PHONY: mpi
mpi: ${MPI_TARGET}
...
I hope it helpful to anyone who meets the same problem.
One approach to solving your problem would be to install (if it is not already installed) one of the 'dummy MPI' libraries available. So long as your code runs correctly on one MPI process (I'm sure you've written it so that it does) then it should run correctly when linked to a dummy MPI library. If you're not familiar with a dummy MPI library, Google.

G++ error: ‘<anonymous>’ has incomplete type

I am forced to use a third party dongle access library that provides an include file 'sense4.h' with code as follows:
#if !defined _WINDOWS_
#define WINAPI
#define CONST const
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef unsigned int UINT;
typedef unsigned long ULONG;
typedef char CHAR;
typedef char TCHAR;
typedef void VOID;
...
#endif /* !defined _WINDOWS */
...
unsigned long WINAPI S4Startup(
VOID
);
unsigned long WINAPI S4Cleanup(
VOID
);
...
The problem is that g++ 4.6.1 complains about lines of code where typedefed VOID is used:
sense4.h:375:9: error: ‘<anonymous>’ has incomplete type
sense4.h:376:1: error: invalid use of ‘VOID {aka void}’
sense4.h:383:9: error: ‘<anonymous>’ has incomplete type
sense4.h:384:1: error: invalid use of ‘VOID {aka void}’
Is there anything I can do without changing the 'sense.h' include file to make my project compile with g++?
Update 1
I found out that the section 18 of C++ Standard Core Language Closed Issues, Revision 30 states:
If the parameter-declaration-clause is empty, the function takes no arguments. The parameter list (void) is equivalent to the empty parameter list.
Can a typedef to void be used instead of the type void in the parameter list?
Rationale: The IS is already clear that this is not allowed.
Quick summary: The code is not valid C++, though there's some lack of clarity about whether it should be. Using void rather than VOID, or just using empty parentheses, will avoid the error.
I think this is a bug in g++.
I thought this was a bug in g++. I'm now convinced that it isn't, though I argue that it would be better to make this a warning rather than a fatal error.
Normally in C++, a function with no parameters is declared with empty parentheses:
int foo();
As a concession to C compatibility, C++ also allows a C-style prototype, using void to indicate that the function has no parameters (since empty parentheses mean something else in C):
int bar(void);
g++'s interpretation seems to be that the void in this syntax here doesn't refer to the incomplete type void; rather, it treats it as a special syntax with a distinct use of the keyword.
I think you'll need to modify the header file to get g++ to accept it.
gcc accepts it as valid C, but that's not helpful if you need to #include it from a C++ source file -- unless you write a C wrapper and invoke it from your C++ code, which might be an acceptable workaround.
(Incidentally, I hate typedefs like that. What's the purpose of typedef void VOID;? Did the author think void was too confusing? I suspect it's for compatibility with very old C compilers that didn't support the void keyword, but the need for that is long past.)
Here's the relevant description from the latest draft of the ISO C++ 2011 standard (8.3.5 [dcl.fct]):
The parameter-declaration-clause determines the arguments that can
be specified, and their processing, when the function is called. [ ...
] If the parameter-declaration-clause is empty, the function takes
no arguments. The parameter list (void) is equivalent to the empty
parameter list. Except for this special case, void shall not be a
parameter type (though types derived from void, such as void*,
can).
This implies that the void keyword in int bar(void); does refer to the type void. Since a typedef name is a synonym for the named type, int bar(VOID); should be equally legal. It would make the most sense for a typedef name like VOID to be accepted in place of void, but the wording of the standard actually refers to the keyword void, not to the type.
The whole purpose of permitting (void) is C compatibility. Just to add to the confusion, the 1990 ISO C standard requires the void keyword; the 1999 and 2011 C standards changed the wording, allowing a typedef instead. The response to C++ Defect Report #577 confirms that the current wording requires the void keyword, and proposes a change that will permit a typedef -- but that change is not yet in any ISO C++ standard. It will probably appear in the first Technical Corrigendum for C++ 2011, whenever it's published.
Thanks to another.anon.coward for finding the existing gcc bug report. I've added an overly verbose comment suggesting that the code is valid and the error message should not be produced -- and a later comment conceding that the code is invalid, but that a warning would be more appropriate than a fatal error.
In the meantime, I suggest contacting the provider of this sense4.h header file. If they intended it to #included only from C code, there's no real problem with it (other than the IMHO poor style); otherwise, they might consider using #ifdef __cplusplus, declaring the functions with (void) in C and with () in C++. And you could go ahead and make that change yourself. Whether g++ should accept the code or not, with a few changes it would be valid C, valid C++, acceptable to both gcc and g++, and better style.
If you've read this far and you're still awake, I'm impressed.

Code compiles in VS2008 but not in VS2010 for std::set with boost::trim

The following code
#include "stdafx.h"
#include <string>
#include <set>
#include <boost/algorithm/string/trim.hpp>
int _tmain(int argc, _TCHAR* argv[])
{
std::set<std::string> test;
test.insert("test1 ");
test.insert("test2 ");
for(std::set<std::string>::iterator iter = test.begin(); iter != test.end(); ++iter)
{
boost::algorithm::trim(*iter);
}
return 0;
}
compiles in VS2008 but fails in VS2010 with the error
error C2663: 'std::basic_string<_Elem,_Traits,_Ax>::erase' : 3 overloads have no legal conversion for 'this' pointer \boost\include\boost\algorithm\string\trim.hpp
which indicates there is a problem with const matching in the functions. If I change set to vector everything is fine. I can also do a
boost::algorithm::trim(const_cast<std::string&>(*iter));
but I hate putting that in my code, and it seems like I shouldn't have to as I'm not using a const iterator on the set. Does anyone have any ideas if this is the intended behavior and why?
The elements of a std::set are intended to be immutable. If you could update them in place, it would either require the set to be re-ordered whenever you updated an element (which would be very hard, possibly impossible, to implement), or updating an element would break the set's guarantee of ordering.
Allowing the elements of a set to be mutable was an oversight in the original C++98 standard. It was corrected in C++11; the new standard requires set iterators to dereference to a const element. VS10 implements the new rule; VS08 followed the old standard, where updating a set element in place invokes undefined behaviour.
(See the final draft C++11 standard, section 23.2.4 para 6.)
Yes, it's intended behavior. Even when you don't use a const_iterator, you normally need to treat the contents of a set as const. Even though the modification you're making (probably) shouldn't cause a problem, modifying them in general could require that the order of the elements be changed to maintain set's invariant that the items are always in order.
To ensure that they stay in order, you aren't allowed to modify them at all.
VS 2008 allowed this, but probably shouldn't have (as in: the standard sort of allowed it, but it definitely wasn't a good idea). VS 2010 fixes the problem (and conforms with the new draft standard) by not allowing in-place modification.
The cure is to remove the item from the set, modify as needed, and then re-insert it into the set (or, as you've done, cast away the const-ness, and pray that nothing you do screws up the ordering).

Resources