I have a class called RenderCommand:
class RenderCommand
{
public:
RenderCommandType commandType;
RenderCommand() : commandType(RenderCommandTypeNone) {};
virtual ~RenderCommand() {};
};
I then have a queue of these RenderCommands which stores unique_ptrs to them:
typedef std::deque<std::unique_ptr<RenderCommand>> RenderQueue;
Finally in a section of code, I create a vector of these RenderQueues, and try to resize it:
std::vector<RenderQueue> queues;
queues.resize(4);
The resize line is giving me a few issues. In clang I get the error message:
call to deleted constructor of 'std::unique_ptr<RenderCommand, std::default_delete<RenderCommand> >'
With GCC 4.8, I just get a whole bunch of errors similar to
required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::_Deque_iterator<std::unique_ptr<RenderCommand>, const std::unique_ptr<RenderCommand>&, const std::unique_ptr<RenderCommand>*>; _ForwardIterator = std::_Deque_iterator<std::unique_ptr<RenderCommand>, std::unique_ptr<RenderCommand>&, std::unique_ptr<RenderCommand>*>; _Tp = std::unique_ptr<RenderCommand>]'
This compiles fine in Visual Studio 2012 however so I'm a little lost. I appreciate any help you guys can give!
EDIT: RenderCommandType is just an enum:
enum RenderCommandType
{
RenderCommandTypeNone = 0,
RenderCommandTypeBeginRepeat,
RenderCommandTypeEndRepeat,
RenderCommandTypeBeginScene,
RenderCommandTypeEndScene,
//etc
};
EDIT2: Ok this seems to be a std::deque problem, changing RenderQueue to:
typedef std::vector<std::unique_ptr<RenderCommand>> RenderQueue;
works. Also removing references to my own class and just using an int still doesn't work (unless like above I replace deque with vector):
std::vector<std::deque<std::unique_ptr<int>>> tempQueue;
tempQueue.resize(4);
:-/
I simplified your example to
#include <deque>
#include <vector>
struct A {
A(const A&) = delete;
};
void f()
{
std::vector<std::deque<A> > q;
q.resize(4);
}
With g++ 4.6, this example compiles fine. From g++ 4.7 on however, it prints a lot of error messages, finally resulting in the mentioned
error: use of deleted function ‘A::A(const A&)’
Replacing deque with vector or list doesn't show this behaviour.
So, it seems this is either a regression from g++ 4.6 to 4.7 or a correction of a previous bug. In any case, I filed a bug report with g++, see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59192
Related
With gcc 10.1 and boost 1.73.0, the following code
#include <boost/bimap.hpp>
int main() {
boost::bimap<int, int> lookup;
}
fails to compile with flags -O2 --std=c++20, but will succeed with flags -O2 -std=c++17 (verified with compiler explorer).
This is possibly related to the following issue: https://github.com/boostorg/bimap/pull/15 (deprecated std::allocator<void>)
Is there some workaround I can use for now to get this code to successfully compile with --std=c++20?
The reason behind the error is not that the std::allocator<void> specialization is removed. Actually, it's still valid as the primary template with the void argument. The code fails to compile, because ::rebind is no longer part of std::allocator itself. Instead, an implementation should use std::allocator_traits<Alloc>::rebind_alloc<U>.
Fortunately, most containers usually allow to specify a custom allocator as a template argument. It's also the case for boost::bimap, where an allocator can be the third, fourth or fifth template parameter, according to docs. It defaults to std::allocator, but instead, boost::container::allocator can be used, which does not produce the error:
#include <boost/bimap.hpp>
#include <boost/container/allocator.hpp>
int main() {
boost::bimap<int, int, boost::container::allocator<int>> lookup;
}
This issue has recently been fixed in 6fba6e5. boost::bimap now properly detects if a nested ::rebind is available:
template<class A, class T, class = void>
struct allocator_rebind {
typedef typename detail::alloc_to<A, T>::type type;
};
template<class A, class T>
struct allocator_rebind<A, T,
typename detail::alloc_void<typename A::template rebind<T>::other>::type> {
typedef typename A::template rebind<T>::other type;
};
The following code (also in https://godbolt.org/z/NSG6Qz) compiles fine in gcc, clang and Visual Studio 2013, but does not compile in recent MSVC versions:
#include <map>
#include <vector>
class MoveOnly {
public:
MoveOnly() {}
MoveOnly(const MoveOnly&) = delete;
MoveOnly& operator=(const MoveOnly&) = delete;
MoveOnly(MoveOnly&&);
MoveOnly& operator=(MoveOnly&&);
};
int main() {
std::vector<std::map<int, MoveOnly>> vecOfMaps;
std::map<int, MoveOnly> map;
vecOfMaps.push_back(std::move(map));
}
The compilation in all MSVC versions in godbolt fails, in v19.22 with these errors (excerpt):
error C2280: 'std::pair<const _Kty,_Ty>::pair(const std::pair<const _Kty,_Ty> &)':
attempting to reference a deleted function
[...]
note: while compiling class template member function
'std::map<int,MoveOnly,std::less<int>,std::allocator<std::pair<const _Kty,_Ty>>>::map(
const std::map<_Kty,_Ty,std::less<int>,std::allocator<std::pair<const _Kty,_Ty>>> &)'
MSVC does not have problems pushing non-copyable objects into a std::map. Pushing non-copyable objects into std::vector works as well. But pushing the map of non-copyable objects into the vector fails.
Why doesn't this compile?
Is there a workaround that can be applied to the MoveOnly class to make this code compile in MSVC, without losing the non-copyable attribute?
In a very simple situation with a constrained constructor, testing for convertibility of the argument, an error is produced in clang, but not in g++:
#include <type_traits>
template <class T, class U>
constexpr bool Convertible = std::is_convertible<T,U>::value && std::is_convertible<U,T>::value;
template <class T>
struct A
{
template <class S, class = std::enable_if_t<Convertible<S,T>> >
A(S const&) {}
};
int main()
{
A<double> s = 1.0;
}
Maybe this issue is related to Is clang's c++11 support reliable?
The error clang gives, reads:
error: no member named 'value' in 'std::is_convertible<double, A<double> >'
constexpr bool Convertible = std::is_convertible<T,U>::value && std::is_convertible<U,T>::value;
~~~~~~~~~~~~~~~~~~~~~~~~~~^
I've tried
g++-5.4, g++-6.2 (no error)
clang++-3.5, clang++-3.8, clang++-3.9 (error)
with argument -std=c++1y and for clang either with -stdlib=libstdc++ or -stdlib=libc++.
Which compiler is correct? Is it a bug in clang or gcc? Or is the behavior for some reasons undefined and thus both compilers correct?
First of all, note that it works fine if you use:
A<double> s{1.0};
Instead, the error comes from the fact that you are doing this:
A<double> s = 1.0;
Consider the line below (extracted from the definition of Convertible):
std::is_convertible<U,T>::value
In your case, this is seen as it follows (once substitution has been performed):
std::is_convertible<double, A<double>>::value
The compiler says this clearly in the error message.
This is because a temporary A<double> is constructed from 1.0, then it is assigned to s.
Note that in your class template you have defined a (more or less) catch-all constructor, so a const A<double> & is accepted as well.
Moreover, remember that a temporary binds to a const reference.
That said, the error happens because in the context of the std::enable_if_t we have that A<double> is an incomplete type and from the standard we have this for std::is_convertible:
From and To shall be complete types [...]
See here for the working draft.
Because of that, I would say that it's an undefined behavior.
As a suggestion, you don't need to use std::enable_if_t in this case.
You don't have a set of functions from which to pick the best one up in your example.
A static_assert is just fine and error messages are nicer:
template <class S>
A(S const&) { static_assert(Convertible<S,T>, "!"); }
Here is the simplified version of the class which is stored as value in a map which works fine in VS2008 (note that all members are private):
class Value{
friend class FriendClass;
friend class std::map<std::string, Value>;
friend struct std::pair<const std::string, Value>;
friend struct std::pair<std::string, Value>;
Value() {..}
Value(Value const& other) {..}
... rest members...
};
Code (called from FriendClass, so this can reach private constructors) :
FriendClass::func()
{
std::map<const std::string, Value> map;
map.insert(std::make_pair(std::string("x"), Value()));
}
This compiles w/o any error in VS2008, but fails on VS2015/C++11:
file.cpp(178): error C2664: 'std::_Tree_iterator>>> std::_Tree>::insert(std::_Tree_const_iterator>>>,const std::pair &)': cannot convert argument 1 from 'std::pair' to 'std::pair &&'
with
[
_Kty=std::string,
_Ty=Value,
_Pr=std::less,
_Alloc=std::allocator>
]
and
[
_Kty=std::string,
_Ty=Value
]
file.cpp(178): note: Reason: cannot convert from 'std::pair' to 'std::pair'
with
[
_Kty=std::string,
_Ty=Value
]
file.cpp(178): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
If I make the Value copy constructor public, it compiles fine in VS2015 as well. But that was private with purpose, and only made available for std::map and std::pair. However, it seems in C++11 additional friend access are also necessary to declare. Which are these?
Thank you.
I don't have access to the compilers you mentioned, but here's what I'm seeing on g++ 5.3.
Consider the following essentially-same version of your question:
#include <map>
#include <utility>
class foo
{
friend std::pair<const int, foo>;
foo(const foo &other){}
public:
foo(){}
};
int main()
{
using map_t = std::map<int, foo>;
map_t m;
m.insert(std::make_pair(2, foo()));
// m.emplace(2, foo());
}
(The default ctor is public, but that's non-essential and just makes the example shorter.)
In main, note the two lines
m.insert(std::make_pair(2, foo()));
// m.emplace(2, foo());
Reversing the comments builds fine, but the version shown doesn't:
/usr/include/c++/5/bits/stl_pair.h: In instantiation of ‘constexpr std::pair<_T1, _T2>::pair(_U1&&, const _T2&) [with _U1 = int; <template-parameter-2-2> = void; _T1 = int; _T2 = foo]’:
/usr/include/c++/5/bits/stl_pair.h:281:72: required from ‘constexpr std::pair<typename std::__decay_and_strip<_Tp>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&) [with _T1 = int; _T2 = foo; typename std::__decay_and_strip<_T2>::__type = foo; typename std::__decay_and_strip<_Tp>::__type = int]’
stuff.cpp:21:34: required from here
stuff.cpp:9:2: error: ‘foo::foo(const foo&)’ is private
foo(const foo &other){}
^
Looking at the source code std_pair.h shows that indeed it is trying to call the copy constructor. Unfortunately, you friended std::pair, but not std::make_pair.
The emplace version doesn't have this problem, but I suspect that this is implementation dependent. In general, if you want a container to store a completely opaque class, I would suggest that you use a container of std::shared_ptrs to them. This allows you to completely specify which function/class can create/copy objects in your own code, and makes no assumptions on the library's code.
I distilled the code and ended up with the one below. Error is when inserting into a map...
Thanks to the person who marked down the question - hopefully he will be the first to answer it ;).
Seriously now, my point is: the fact that move is done on a "best effort" basis and that one cannot ensure it is used (as here with a naive delete) makes room for a lot of confusion. To me it's dodgy one has to provide a never used copy constructor body just to silence the compiler.
Of course, may be a bad play between the compiler and my stl. Leaving the people who live and breathe the C++ standard to clarify.
#include <vector>
#include <map>
#include <iostream>
using namespace std;
struct FeedDataType
{
FeedDataType() {};
FeedDataType(FeedDataType&& ) = default;
#if 0
// error: use of deleted function 'FeedDataType::FeedDataType(const FeedDataType&) - why?
FeedDataType(const FeedDataType& ) = delete;
#else
// Compiles ok but never called. But cannot mark it delete...
FeedDataType(const FeedDataType& ) { cout << "Never called!" << endl; };
#endif
};
int main ()
{
vector< FeedDataType > x;
map<int, vector< FeedDataType > > mymap;
mymap.insert( std::make_pair( 0, x ) );
}
Error:
In file included from /cs/insight_san/tools/usr/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/vector:63:0,
from play3.cpp:1:
/cs/insight_san/tools/usr/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = FeedDataType; _Args = {const FeedDataType&}]':
/cs/insight_san/tools/usr/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_uninitialized.h:77:3: required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const FeedDataType*, std::vector<FeedDataType> >; _ForwardIterator = FeedDataType*; bool _TrivialValueTypes = false]'
/cs/insight_san/tools/usr/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_uninitialized.h:119:41: required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const FeedDataType*, std::vector<FeedDataType> >; _ForwardIterator = FeedDataType*]'
/cs/insight_san/tools/usr/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_uninitialized.h:260:63: required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const FeedDataType*, std::vector<FeedDataType> >; _ForwardIterator = FeedDataType*; _Tp = FeedDataType]'
/cs/insight_san/tools/usr/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_vector.h:310:9: required from 'std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = FeedDataType; _Alloc = std::allocator<FeedDataType>; std::vector<_Tp, _Alloc> = std::vector<FeedDataType>]'
/cs/insight_san/tools/usr/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_pair.h:137:64: required from 'constexpr std::pair<_T1, _T2>::pair(_U1&&, _U2&&) [with _U1 = int; _U2 = std::vector<FeedDataType>&; <template-parameter-2-3> = void; _T1 = int; _T2 = std::vector<FeedDataType>]'
/cs/insight_san/tools/usr/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_pair.h:273:72: required from 'constexpr std::pair<typename std::__decay_and_strip<_T1>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&) [with _T1 = int; _T2 = std::vector<FeedDataType>&; typename std::__decay_and_strip<_T2>::__type = std::vector<FeedDataType>; typename std::__decay_and_strip<_T1>::__type = int]'
play3.cpp:24:44: required from here
/cs/insight_san/tools/usr/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_construct.h:77:7: error: use of deleted function 'FeedDataType::FeedDataType(const FeedDataType&)'
play3.cpp:13:9: error: declared here
ORIGINAL POST:
There is a compiler error (g++ 4.7.2 on RedHat) I'd like to clarify.
What is all about: simply want to enforce the use of the move constructor only.
So I write:
FeedDataType(FeedDataType&& ) = default;
FeedDataType(const FeedDataType& ) = delete;
Alas, it doesn't compile (I'll spare you the full stack trace):
.../lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_construct.h:77:7: error: use of deleted function 'FeedDataType::FeedDataType(const FeedDataType&)'
Not being obvious where copy ctor required, I write a body for it to let the program core when used and then look at the stack trace:
FeedDataType(FeedDataType&& ) = default;
FeedDataType(const FeedDataType& ) { cerr << "Called" << endl; assert(false); }
Well, the program compiles and runs without entering the copy ctor code. So, if not used, why cannot the copy ctor be deleted? How can one be sure of what is being used?
Other thing that I don't get:
void FeedData::add( const FeedDataType & feedDataRow )
{
// Is move used here? If not why not warn?
some_vector.push_back( std::move(feedDataRow) );
}
This apparently uses the copy constructor. Would have been good having a warning/error from the compiler that move construction was not in use here? In large programs it would be easy to miss the const and believe that std::move would do the job. In fact, should have been a compiler error - feedDataRow is const, move construction from it should not be possible?
Using non-const reference appears to be better as the move constructor is used in that case. Or should one pass here by value?
I think the first issue is a compiler bug, but would like to be enlightened by someone who knows what was going on. I was thinking move semantics is easy but obviously need to do my homework. Looking for Mr. Meyers books on C++11 ;).
Thanks,
Adrian
Well, the program compiles and runs without entering the copy ctor code.
So, if not used, why cannot the copy ctor be deleted?
How can one be sure of what is being used?
It may be in a scope where it may be use
in the following code:
void foo() = delete;
void bar(bool b)
{
if (b) { foo(); }
// Other stuff
}
Suppose that we call only bar(false), foo is not called, but bar use a deleted function anyway.
If you follow the error link, you will see in which part of code Copy Constructor may be used.
std::move means, approximately, "move if you can, otherwise copy" (not quite, but close enough for purposes of this discussion). It does not mean "move if you can, otherwise panic". The former semantics is useful most everywhere, including virtually all situations of writing template-based generic components. The latter is only useful in rare cases when moving might be impossible, and copying might be possible, but you don't want to copy.
The standard gives you the former semantics but not the latter. If you need the latter, you can write your own along these lines:
template< class T >
typename std::remove_reference<T>::type&& my_move( T&& t )
{
return static_cast<typename std::remove_reference<T>::type&&>(t);
}
template< class T >
typename std::remove_reference<T>::type&& my_move( const T& t )
{
static_assert(!std::is_lvalue_reference<T&>::value, "Move is requested, but only copying is possible");
}
The copy constructor is used by the copy constructor of vector, which is used by the constructor of std::pair called in std::make_pair. The reason it's not actually called in a given run of your little example program is that the vector is empty.
Try std::move on the x when you call make_pair.