Does initializing a vector with one element require copy constructor? - c++

The following example complies in clang but fails in GCC.
Original link
Code:
#include<vector>
struct Foo
{
Foo() = default;
Foo(Foo&&) = default;
};
Foo baz(std::vector<Foo> foos);
Foo bar1(Foo&& foo_)
{
std::vector<Foo> foos{std::move(foo_)};
return baz(std::move(foos));
}
Foo bar2(Foo&& foo_)
{
std::vector<Foo> foos;
foos.push_back(std::move(foo_));
return baz(std::move(foos));
}
template<typename... Foos>
Foo bar3(Foo&& foo_, Foos&&... foos_)
{
std::vector<Foo> foos{std::move(foo_), std::forward<Foos>(foos_)...};
return baz(std::move(foos));
}
void dummy()
{
Foo f1, f2;
bar3(std::move(f1), std::move(f2));
}
Errors:
In file included from /opt/gcc-4.9.0/include/c++/4.9.0/vector:62:0,
from /tmp/gcc-explorer-compiler11512-1-c5m2m1/example.cpp:1:
/opt/gcc-4.9.0/include/c++/4.9.0/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = Foo; _Args = {const Foo&}]':
/opt/gcc-4.9.0/include/c++/4.9.0/bits/stl_uninitialized.h:75:53: required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const Foo*; _ForwardIterator = Foo*; bool _TrivialValueTypes = false]'
/opt/gcc-4.9.0/include/c++/4.9.0/bits/stl_uninitialized.h:125:41: required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const Foo*; _ForwardIterator = Foo*]'
/opt/gcc-4.9.0/include/c++/4.9.0/bits/stl_uninitialized.h:278:63: required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = const Foo*; _ForwardIterator = Foo*; _Tp = Foo]'
/opt/gcc-4.9.0/include/c++/4.9.0/bits/stl_vector.h:1286:27: required from 'void std::vector<_Tp, _Alloc>::_M_range_initialize(_ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const Foo*; _Tp = Foo; _Alloc = std::allocator<Foo>]'
/opt/gcc-4.9.0/include/c++/4.9.0/bits/stl_vector.h:378:36: required from 'std::vector<_Tp, _Alloc>::vector(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = Foo; _Alloc = std::allocator<Foo>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<Foo>]'
13 : required from here
/opt/gcc-4.9.0/include/c++/4.9.0/bits/stl_construct.h:75:7: error: use of deleted function 'constexpr Foo::Foo(const Foo&)'
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^
3 : note: 'constexpr Foo::Foo(const Foo&)' is implicitly declared as deleted because 'Foo' declares a move constructor or move assignment operator
struct Foo
^
Compilation failed
If it is a bug in GCC, can someone suggest an easy workaround for bar3 function?

It's not possible to move out of an initializer_list, so the corresponding constructor of std::vector has to copy. That's why you're getting the errors. bar2 should compile without errors.
The normal template pack expansion trick to repeatedly call push_back should work on the variadic version.

Related

std::unique_ptr use of deleted function with move

there is the following code:
struct RenderableAtmosphere {
std::unique_ptr<Atmosphere> atmosphere;
float hScaleFactor, parentEarthSizeCoefficient;
bool isUseToneMapping = false;
};
struct RenderableSceneComponent {
...
std::vector<RenderableAtmosphere> atmospheres;
};
...
RenderableSceneComponent uranusSystemComponent;
uranusSystemComponent.atmospheres = vector<RenderableAtmosphere>{move(renderableUranusAtmosphere)};
//uranusSystemComponent.atmospheres.push_back(move(renderableUranusAtmosphere));
In the case of a move assignment operator call, the code does not compile with the following set of errors:
In file included from D:/MinGW/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/vector:62,
from D:\Clion\OpenGL_Projects\CourseWork_SolarSystem\src\Auxiliary_Modules/Camera.h:5,
from D:\Clion\OpenGL_Projects\CourseWork_SolarSystem\src\Auxiliary_Modules/AuxiliaryModules.h:4,
from D:\Clion\OpenGL_Projects\CourseWork_SolarSystem\src\Application.h:3,
from D:\Clion\OpenGL_Projects\CourseWork_SolarSystem\src\Application.cpp:1:
D:/MinGW/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = RenderableAtmosphere; _Args = {const RenderableAtmosphere&}]':
D:/MinGW/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_uninitialized.h:83:18: required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const RenderableAtmosphere*; _ForwardIterator = RenderableAtmosphere*; bool _TrivialValueTypes = false]'
D:/MinGW/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_uninitialized.h:134:15: required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const RenderableAtmosphere*; _ForwardIterator = RenderableAtmosphere*]'
D:/MinGW/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_uninitialized.h:289:37: required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = const RenderableAtmosphere*; _ForwardIterator = RenderableAtmosphere*; _Tp = RenderableAtmosphere]'
D:/MinGW/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_vector.h:1464:33: required from 'void std::vector<_Tp, _Alloc>::_M_range_initialize(_ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const RenderableAtmosphere*; _Tp = RenderableAtmosphere; _Alloc = std::allocator<RenderableAtmosphere>]'
D:/MinGW/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_vector.h:519:2: required from 'std::vector<_Tp, _Alloc>::vector(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = RenderableAtmosphere; _Alloc = std::allocator<RenderableAtmosphere>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<RenderableAtmosphere>]'
D:\Clion\OpenGL_Projects\CourseWork_SolarSystem\src\Application.cpp:888:102: required from here
D:/MinGW/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_construct.h:75:7: error: use of deleted function 'RenderableAtmosphere::RenderableAtmosphere(const RenderableAtmosphere&)'
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
I cannot figure out at what point a copy of the class is called, which tries to call the deleted copy constructor on unique_ptr. But if you use push_back, then everything works.
The statement
uranusSystemComponent.atmospheres = vector<RenderableAtmosphere>{move(renderableUranusAtmosphere)};
calls the assignment operator of vector:
vector& operator=( const vector& other );
which requires a copy constructor for RenderableAtmosphere with the signature:
RenderableAtmosphere::RenderableAtmosphere(const RenderableAtmosphere&)
But RenderableAtmosphere does not have such a copy constructor since it has a std::unique_ptr member. Copy Constructors on cppreference.com
That's the reason why you get these error messages.

Why is the copy constructor being called for the construction of an empty unique_ptr vector?

#include <vector>
#include <memory>
#include <iostream>
class A {
std::vector<std::unique_ptr<int>> vec;
public:
virtual ~A() = 0;
};
A::~A() {}
class B : public A {
public:
B() {}
};
int main () {
B b = B();
return 0;
}
Above is a minimal reproducible example. It does not compile, and the following error message is given:
me:~ $ g++ main2.cc
In file included from /usr/include/c++/7/vector:62:0,
from main2.cc:1:
/usr/include/c++/7/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = std::unique_ptr<int>; _Args = {const std::unique_ptr<int, std::default_delete<int> >&}]’:
/usr/include/c++/7/bits/stl_uninitialized.h:83:18: required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >; _ForwardIterator = std::unique_ptr<int>*; bool _TrivialValueTypes = false]’
/usr/include/c++/7/bits/stl_uninitialized.h:134:15: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >; _ForwardIterator = std::unique_ptr<int>*]’
/usr/include/c++/7/bits/stl_uninitialized.h:289:37: required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >; _ForwardIterator = std::unique_ptr<int>*; _Tp = std::unique_ptr<int>]’
/usr/include/c++/7/bits/stl_vector.h:331:31: required from ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = std::unique_ptr<int>; _Alloc = std::allocator<std::unique_ptr<int> >]’
main2.cc:5:7: required from here
/usr/include/c++/7/bits/stl_construct.h:75:7: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/7/memory:80:0,
from main2.cc:2:
/usr/include/c++/7/bits/unique_ptr.h:388:7: note: declared here
unique_ptr(const unique_ptr&) = delete;
^~~~~~~~~~
What it all seems like is that the copy constructor for the unique_ptr is being called somewhere.
But I have no idea why it would be called at all. When a vector is initialized, it has size 0, right? Under that assumption, no unique_ptr should be constructed.
What is the source of my compilation error?
B b = B() is a copy-initialisation and, until C++17, required that the copy be valid (even if it ended up being elided).
Even though the size of the vector in that copy is zero, that is not something that can be statically known by the innards of the copy machinery during compile-time. So, the code to make it work must be "known" during compilation, so that it is available at runtime if needed.
You probably meant just a normal declaration: B b;.
The original approach would actually have been enough if your class were trivially-moveable (because a unique_ptr can be moved), but by giving it a user-declared destructor you pessimised it. Unless you actually have a strong reason to want this class to be polymorphic, don't do that. Use = default or just omit the destructor entirely; it's not doing anything useful.

Creating and storing string in a union inside a struct in a vector C++14 (Unrestricted Union)

Can anyone please explain how to assign and push a string(in a union inside a struct) into a vector? Is this possible? Is the vector trying to access invalid memory?
#include <iostream>
#include <string>
#include <vector>
using namespace std;
typedef struct {
int height;
int width;
} Page;
typedef struct varstruct{
int test;
union uni{
Page page;
int intVar;
string stringVar;
uni(){
new (&stringVar) std::string();
}
~uni(){}
} VarUnion;
varstruct(){}
~varstruct(){}
} VariableDataStruct;
vector<VariableDataStruct> List;
int main()
{
VariableDataStruct structeg;
structeg.test = 1;
structeg.VarUnion.stringVar = "Test";
List.push_back(structeg);
cout<<structeg.VarUnion.stringVar<<endl;
structeg.VarUnion.stringVar.~basic_string();
return 0;
}
The code works fine in the absence "List.push_back(structeg);" statement. On addition of this statement gives the following errors:
In file included from /usr/include/c++/4.8.3/x86_64-redhat-linux/bits/c++allocator.h:33:0,
from /usr/include/c++/4.8.3/bits/allocator.h:46,
from /usr/include/c++/4.8.3/string:41,
from /usr/include/c++/4.8.3/bits/locale_classes.h:40,
from /usr/include/c++/4.8.3/bits/ios_base.h:41,
from /usr/include/c++/4.8.3/ios:42,
from /usr/include/c++/4.8.3/ostream:38,
from /usr/include/c++/4.8.3/iostream:39,
from unionstring2.cc:1:
/usr/include/c++/4.8.3/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = varstruct; _Args = {const varstruct&}; _Tp = varstruct]’:
/usr/include/c++/4.8.3/bits/alloc_traits.h:254:4: required from ‘static typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = varstruct; _Args = {const varstruct&}; _Alloc = std::allocator<varstruct>; typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type = void]’
/usr/include/c++/4.8.3/bits/alloc_traits.h:393:57: required from ‘static decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = varstruct; _Args = {const varstruct&}; _Alloc = std::allocator<varstruct>; decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = <type error>]’
/usr/include/c++/4.8.3/bits/stl_vector.h:906:34: required from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = varstruct; _Alloc = std::allocator<varstruct>; std::vector<_Tp, _Alloc>::value_type = varstruct]’
unionstring2.cc:34:28: required from here
/usr/include/c++/4.8.3/ext/new_allocator.h:120:4: error: use of deleted function ‘varstruct::varstruct(const varstruct&)’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^
unionstring2.cc:12:16: note: ‘varstruct::varstruct(const varstruct&)’ is implicitly deleted because the default definition would be ill-formed:
typedef struct varstruct{
^
unionstring2.cc:12:16: error: use of deleted function ‘varstruct::uni::uni(const varstruct::uni&)’
unionstring2.cc:14:19: note: ‘varstruct::uni::uni(const varstruct::uni&)’ is implicitly deleted because the default definition would be ill-formed:
union uni{
^
unionstring2.cc:17:10: error: union member ‘varstruct::uni::stringVar’ with non-trivial ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
string stringVar;
^
In file included from /usr/include/c++/4.8.3/vector:62:0,
from unionstring2.cc:3:
/usr/include/c++/4.8.3/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = varstruct; _Args = {varstruct}]’:
/usr/include/c++/4.8.3/bits/stl_uninitialized.h:75:53: required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<varstruct*>; _ForwardIterator = varstruct*; bool _TrivialValueTypes = false]’
/usr/include/c++/4.8.3/bits/stl_uninitialized.h:117:41: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<varstruct*>; _ForwardIterator = varstruct*]’
/usr/include/c++/4.8.3/bits/stl_uninitialized.h:258:63: required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<varstruct*>; _ForwardIterator = varstruct*; _Tp = varstruct]’
/usr/include/c++/4.8.3/bits/stl_uninitialized.h:281:69: required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = varstruct*; _ForwardIterator = varstruct*; _Allocator = std::allocator<varstruct>]’
/usr/include/c++/4.8.3/bits/vector.tcc:415:43: required from ‘void std::vector<_Tp, _Alloc>::_M_emplace_back_aux(_Args&& ...) [with _Args = {const varstruct&}; _Tp = varstruct; _Alloc = std::allocator<varstruct>]’
/usr/include/c++/4.8.3/bits/stl_vector.h:911:27: required from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = varstruct; _Alloc = std::allocator<varstruct>; std::vector<_Tp, _Alloc>::value_type = varstruct]’
unionstring2.cc:34:28: required from here
/usr/include/c++/4.8.3/bits/stl_construct.h:75:7: error: use of deleted function ‘varstruct::varstruct(const varstruct&)’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
Is there any alternative?
One of members of your union is string, according to reference
If a union contains a non-static data member with a non-trivial
special member function (copy/move constructor, copy/move assignment,
or destructor), that function is deleted by default in the union and
needs to be defined explicitly by the programmer.
so you cannot compile because during the call of vector::push_back copy constructor of uni is called, but this function is deleted. If you want to compile your code you need to add copy constructor:
uni(const uni& u) {
new (&stringVar) std::string{u.stringVar};
}
then your code compiles and even works, but it is not good approach to use union with non-trivial types. You should add type member to your struct to control which type of your union is active. Then you can delete in destructor the right member (call destructor for non-trivial types). Good example is presented in Bjarne Stroustrup book C++ Programming Language , chapter Anonymous Unions.
Modified version (it is not full code, only IDEA) of your code with type member in struct:
enum TYPE {INT,STR,PAGE};
typedef struct varstruct{
int test;
union {
Page page;
int intVar;
string stringVar;
};
void setPage (Page p) {
if (type == STR)
stringVar.~string();
page = p;
type = PAGE;
}
void setInt (int i) {
if (type == STR)
stringVar.~string();
intVar = i;
type = INT;
}
void setString (string s) {
if (type == STR)
stringVar = s;
else
new (&stringVar) std::string{s};
type = STR;
}
TYPE type = INT;
varstruct (const varstruct& v) {
if (v.type == STR)
new (&stringVar) std::string{v.stringVar};
else if (v.type == INT)
intVar = v.intVar;
else if (v.type == PAGE)
page = v.page;
type = v.type;
}
varstruct(){}
~varstruct(){
if (type == STR)
stringVar.~string();
}
} VariableDataStruct;
and the code in main:
VariableDataStruct structeg;
structeg.test = 1;
structeg.setString("Test");
List.push_back(structeg);
cout<<structeg.stringVar<<endl;

Create vector of mocked class in google test

Is it possible to build a vector of mocked objects in Google Test/Mock? I have a scenario, where I want to return a vector of custom objects (Foo) from an object (Bar). So I was trying return vector with mocked version of that class (std::vector<Foo>).
Example code:
class Foo {
public:
virtual int op(int a , int b) {
return 0;
}
};
class Bar {
public:
virtual std::vector<Foo> getFoos() {
std::vector<Foo> v;
// ...
// Some logic to fill this vector
// ...
return v;
}
};
class MockFoo : public Foo {
public:
MOCK_METHOD2(op, int(int, int));
};
class MockBar : public Bar {
public:
MOCK_METHOD0(getFoos, std::vector<Foo>());
};
TEST(Foo, test_op) {
vector<MockFoo> v;
v.emplace_back();
ASSERT_EQ(v.size(), 1);
MockBar bar;
EXPECT_CALL(bar, getFoos())
.WillRepeatedly(Return(v));
}
I am getting
In file included from .../googlemock/include/gmock/gmock.h:58:0,
from .../FooBarTest.cpp:2:
.../googlemock/include/gmock/gmock-actions.h: In instantiation of ‘testing::internal::ReturnAction<R>::Impl<R_, F>::Impl(const testing::internal::linked_ptr<T>&) [with R_ = std::vector<MockFoo>; F = std::vector<Foo>(); R = std::vector<MockFoo>]’:
.../googlemock/include/gmock/gmock-actions.h:557:44: required from ‘testing::internal::ReturnAction<R>::operator testing::Action<Func>() const [with F = std::vector<Foo>(); R = std::vector<MockFoo>]’
.../FooBarTest.cpp:65:38: required from here
.../googlemock/include/gmock/gmock-actions.h:577:39: error: no matching function for call to ‘ImplicitCast_(std::vector<MockFoo>&)’
value_(ImplicitCast_<Result>(value_before_cast_)) {}
^
In file included from .../googletest/include/gtest/internal/gtest-internal.h:40:0,
from .../googletest/include/gtest/gtest.h:58,
from .../FooBarTest.cpp:1:
.../googletest/include/gtest/internal/gtest-port.h:1343:11: note: candidate: template<class To> To testing::internal::ImplicitCast_(To)
inline To ImplicitCast_(To x) { return x; }
^
.../googletest/include/gtest/internal/gtest-port.h:1343:11: note: template argument deduction/substitution failed:
In file included from .../googlemock/include/gmock/gmock.h:58:0,
from .../FooBarTest.cpp:2:
.../googlemock/include/gmock/gmock-actions.h:577:39: note: cannot convert ‘((testing::internal::ReturnAction<std::vector<MockFoo> >::Impl<std::vector<MockFoo>, std::vector<Foo>()>*)this)->testing::internal::ReturnAction<std::vector<MockFoo> >::Impl<std::vector<MockFoo>, std::vector<Foo>()>::value_before_cast_’ (type ‘std::vector<MockFoo>’) to type ‘std::vector<Foo>’
value_(ImplicitCast_<Result>(value_before_cast_)) {}
^
In file included from /usr/include/c++/5/vector:62:0,
from .../googletest/include/gtest/gtest.h:56,
from .../FooBarTest.cpp:1:
/usr/include/c++/5/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = MockFoo; _Args = {const MockFoo&}]’:
/usr/include/c++/5/bits/stl_uninitialized.h:75:18: required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const MockFoo*, std::vector<MockFoo> >; _ForwardIterator = MockFoo*; bool _TrivialValueTypes = false]’
/usr/include/c++/5/bits/stl_uninitialized.h:126:15: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const MockFoo*, std::vector<MockFoo> >; _ForwardIterator = MockFoo*]’
/usr/include/c++/5/bits/stl_uninitialized.h:281:37: required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const MockFoo*, std::vector<MockFoo> >; _ForwardIterator = MockFoo*; _Tp = MockFoo]’
/usr/include/c++/5/bits/stl_vector.h:322:31: required from ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = MockFoo; _Alloc = std::allocator<MockFoo>]’
.../FooBarTest.cpp:65:37: required from here
/usr/include/c++/5/bits/stl_construct.h:75:7: error: use of deleted function ‘MockFoo::MockFoo(const MockFoo&)’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^
.../FooBarTest.cpp:40:7: note: ‘MockFoo::MockFoo(const MockFoo&)’ is implicitly deleted because the default definition would be ill-formed:
class MockFoo : public Foo {
^
.../FooBarTest.cpp:40:7: error: use of deleted function ‘testing::internal::FunctionMocker<int(int, int)>::FunctionMocker(const testing::internal::FunctionMocker<int(int, int)>&)’
In file included from .../googlemock/include/gmock/gmock.h:61:0,
from .../FooBarTest.cpp:2:
.../googlemock/include/gmock/gmock-generated-function-mockers.h:106:7: note: ‘testing::internal::FunctionMocker<int(int, int)>::FunctionMocker(const testing::internal::FunctionMocker<int(int, int)>&)’ is implicitly deleted because the default definition would be ill-formed:
class FunctionMocker<R(A1, A2)> : public
^
In file included from .../googletest/include/gtest/internal/gtest-internal.h:40:0,
from .../googletest/include/gtest/gtest.h:58,
from .../FooBarTest.cpp:1:
.../googlemock/include/gmock/gmock-spec-builders.h:1784:35: error: ‘testing::internal::FunctionMockerBase<F>::FunctionMockerBase(const testing::internal::FunctionMockerBase<F>&) [with F = int(int, int)]’ is private
GTEST_DISALLOW_COPY_AND_ASSIGN_(FunctionMockerBase);
^
.../googletest/include/gtest/internal/gtest-port.h:875:3: note: in definition of macro ‘GTEST_DISALLOW_COPY_AND_ASSIGN_’
type(type const &);\
^
In file included from .../googlemock/include/gmock/gmock.h:61:0,
from .../FooBarTest.cpp:2:
.../googlemock/include/gmock/gmock-generated-function-mockers.h:106:7: error: within this context
class FunctionMocker<R(A1, A2)> : public
^
In file included from /usr/include/c++/5/vector:62:0,
from .../googletest/include/gtest/gtest.h:56,
from .../FooBarTest.cpp:1:
/usr/include/c++/5/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = MockFoo; _Args = {MockFoo}]’:
/usr/include/c++/5/bits/stl_uninitialized.h:75:18: required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<MockFoo*>; _ForwardIterator = MockFoo*; bool _TrivialValueTypes = false]’
/usr/include/c++/5/bits/stl_uninitialized.h:126:15: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<MockFoo*>; _ForwardIterator = MockFoo*]’
/usr/include/c++/5/bits/stl_uninitialized.h:281:37: required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<MockFoo*>; _ForwardIterator = MockFoo*; _Tp = MockFoo]’
/usr/include/c++/5/bits/stl_uninitialized.h:303:2: required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = MockFoo*; _ForwardIterator = MockFoo*; _Allocator = std::allocator<MockFoo>]’
/usr/include/c++/5/bits/vector.tcc:422:8: required from ‘void std::vector<_Tp, _Alloc>::_M_emplace_back_aux(_Args&& ...) [with _Args = {}; _Tp = MockFoo; _Alloc = std::allocator<MockFoo>]’
/usr/include/c++/5/bits/vector.tcc:101:23: required from ‘void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = MockFoo; _Alloc = std::allocator<MockFoo>]’
.../FooBarTest.cpp:56:20: required from here
/usr/include/c++/5/bits/stl_construct.h:75:7: error: use of deleted function ‘MockFoo::MockFoo(MockFoo&&)’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^
.../FooBarTest.cpp:40:7: note: ‘MockFoo::MockFoo(MockFoo&&)’ is implicitly deleted because the default definition would be ill-formed:
class MockFoo : public Foo {
^
.../FooBarTest.cpp:40:7: error: use of deleted function ‘testing::internal::FunctionMocker<int(int, int)>::FunctionMocker(testing::internal::FunctionMocker<int(int, int)>&&)’
In file included from .../googlemock/include/gmock/gmock.h:61:0,
from .../FooBarTest.cpp:2:
.../googlemock/include/gmock/gmock-generated-function-mockers.h:106:7: note: ‘testing::internal::FunctionMocker<int(int, int)>::FunctionMocker(testing::internal::FunctionMocker<int(int, int)>&&)’ is implicitly deleted because the default definition would be ill-formed:
class FunctionMocker<R(A1, A2)> : public
^
In file included from .../googletest/include/gtest/internal/gtest-internal.h:40:0,
from .../googletest/include/gtest/gtest.h:58,
from .../FooBarTest.cpp:1:
.../googlemock/include/gmock/gmock-spec-builders.h:1784:35: error: ‘testing::internal::FunctionMockerBase<F>::FunctionMockerBase(const testing::internal::FunctionMockerBase<F>&) [with F = int(int, int)]’ is private
GTEST_DISALLOW_COPY_AND_ASSIGN_(FunctionMockerBase);
^
.../googletest/include/gtest/internal/gtest-port.h:875:3: note: in definition of macro ‘GTEST_DISALLOW_COPY_AND_ASSIGN_’
type(type const &);\
^
In file included from .../googlemock/include/gmock/gmock.h:61:0,
from .../FooBarTest.cpp:2:
.../googlemock/include/gmock/gmock-generated-function-mockers.h:106:7: error: within this context
class FunctionMocker<R(A1, A2)> : public
To my best understanding it is due to the fact Google test mock classes are not copyable. I explicitly don't need a copyable mock class. I just need the ability to return list of mocked object. Is it possible in Google test (release-1.8.0)?
One alternative that comes to mind is implement an iterator like patter in Bar, so that it behaves like a vector. However, I want to avoid that approach if possible.
You need to implement a copy constructor inside your Mockclass, that's how I managed to create a mock class vector. Probably something like this:
MockClass(const MockClass& other) {
setDefaultBehaviors();
defaultId = other.defaultId;
}

Why the below code does not compile with gcc but compiles fine with clang

Below code compiles fine with clang but not gcc , any explanation is this a bug in gcc?
Its just a class which contains a vector of unique_ptr and std::function as member and when I create vector of this class , I cant say reserve or resize on this. push_back works fine with std::move, while this only happens with gcc and not clang.
#include <algorithm>
#include <memory>
#include <utility>
#include <iostream>
#include <vector>
#include <functional>
using namespace std;
class ABC
{
public:
ABC()
{}
private:
std::vector<std::unique_ptr<int>> up;
std::function<void (int*)> func;
};
int main()
{
ABC a;
std::vector<ABC> vec;
vec.reserve(1);
}
Error message looks like below for gcc
In file included from /opt/wandbox/gcc-7.1.0/include/c++/7.1.0/bits/stl_tempbuf.h:60:0,
from /opt/wandbox/gcc-7.1.0/include/c++/7.1.0/bits/stl_algo.h:62,
from /opt/wandbox/gcc-7.1.0/include/c++/7.1.0/algorithm:62,
from prog.cc:1:
/opt/wandbox/gcc-7.1.0/include/c++/7.1.0/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = std::unique_ptr<int>; _Args = {const std::unique_ptr<int, std::default_delete<int> >&}]':
/opt/wandbox/gcc-7.1.0/include/c++/7.1.0/bits/stl_uninitialized.h:83:18: required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >; _ForwardIterator = std::unique_ptr<int>*; bool _TrivialValueTypes = false]'
/opt/wandbox/gcc-7.1.0/include/c++/7.1.0/bits/stl_uninitialized.h:134:15: required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >; _ForwardIterator = std::unique_ptr<int>*]'
/opt/wandbox/gcc-7.1.0/include/c++/7.1.0/bits/stl_uninitialized.h:289:37: required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >; _ForwardIterator = std::unique_ptr<int>*; _Tp = std::unique_ptr<int>]'
/opt/wandbox/gcc-7.1.0/include/c++/7.1.0/bits/stl_vector.h:331:31: required from 'std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = std::unique_ptr<int>; _Alloc = std::allocator<std::unique_ptr<int> >]'
prog.cc:10:7: required from 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = ABC; _Args = {const ABC&}]'
/opt/wandbox/gcc-7.1.0/include/c++/7.1.0/bits/stl_uninitialized.h:83:18: required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const ABC*; _ForwardIterator = ABC*; bool _TrivialValueTypes = false]'
/opt/wandbox/gcc-7.1.0/include/c++/7.1.0/bits/stl_uninitialized.h:134:15: required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const ABC*; _ForwardIterator = ABC*]'
/opt/wandbox/gcc-7.1.0/include/c++/7.1.0/bits/stl_uninitialized.h:289:37: required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = const ABC*; _ForwardIterator = ABC*; _Tp = ABC]'
/opt/wandbox/gcc-7.1.0/include/c++/7.1.0/bits/stl_vector.h:1263:35: required from 'std::vector<_Tp, _Alloc>::pointer std::vector<_Tp, _Alloc>::_M_allocate_and_copy(std::vector<_Tp, _Alloc>::size_type, _ForwardIterator, _ForwardIterator) [with _ForwardIterator = const ABC*; _Tp = ABC; _Alloc = std::allocator<ABC>; std::vector<_Tp, _Alloc>::pointer = ABC*; std::vector<_Tp, _Alloc>::size_type = long unsigned int]'
/opt/wandbox/gcc-7.1.0/include/c++/7.1.0/bits/vector.tcc:73:40: required from 'void std::vector<_Tp, _Alloc>::reserve(std::vector<_Tp, _Alloc>::size_type) [with _Tp = ABC; _Alloc = std::allocator<ABC>; std::vector<_Tp, _Alloc>::size_type = long unsigned int]'
prog.cc:24:18: required from here
/opt/wandbox/gcc-7.1.0/include/c++/7.1.0/bits/stl_construct.h:75:7: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]'
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /opt/wandbox/gcc-7.1.0/include/c++/7.1.0/memory:80:0,
from prog.cc:2:
/opt/wandbox/gcc-7.1.0/include/c++/7.1.0/bits/unique_ptr.h:388:7: note: declared here
unique_ptr(const unique_ptr&) = delete;
^~~~~~~~~~
This happens because std::function's move ctor is not noexcept, but a std::vector can only use the move ctor if it's noexcept (strong exception guarantee).
The issue is that std::unique_ptr is (obviously) non-copyable, so that makes ABC noncopyable as a whole.
To make ABC noexcept-movable implicitly, it'd need every one of its members to be noexcept-movable as well.
If you remove the std::function, that's what happens: the .resize() doesn't need to copy A.up (a std::vector's move operator is noexcept), so the std::unique_ptrs (inside up) can just be moved, and everything works fine.
See this coliru: if you comment the noexcept, vec.reserve() will need to copy everything, and the issue comes back.
Adding ABC(ABC&&) = default fixes the issue because user-declared (though defaulted) move ctor inhibits the generation of copy constructor (see here).
We can also go the opposite way and manually delete A's copy constructor in the coliru (and keep the move ctor not noexcept): here.
To fix the issue, you could store the std::function in a std::unique_ptr, which has a nothrow move ctor. See here
I think that GCC is being picky about constructors; it blocks the generation of the move-ctor1. It stops complaining after you provide them explicitely:
class ABC
{
public:
ABC() = default; // <--
ABC(ABC&&) = default; // <--
private:
std::vector<std::unique_ptr<int>> up;
std::function<void (int*)> func;
};
1 I think (again, I'm not sure), that his happens because the default copy-ctor of ABC is defined as noexcept and is as such preferred over the default move-ctor (it's still ill-formed because we're dealing with non-copyable members here). Trying to generate a defaulted noexcept move-ctor result in:
main.cpp:14:4: note: 'ABC::ABC(ABC&&) noexcept' is implicitly deleted because its exception-specification does not match the implicit exception-specification ''
ABC(ABC&&) noexcept = default;
^~~
As such, forcing the generation of no-noexcept move-ctor allows it to be picked. Why Clang doesn't have a problem with that - I don't know.
One explanation for the above is hinted by the fact that removing std::function allows the defaulted noexcept move-ctor to be generated. std::function doesn't have a noexcept move-ctor (which sucks tremendously), so the whole class falls back to the copy-ctor. Since unique_ptr doesn't have one, the whole thing breaks.
GCC accepted the lack of noexcept on std::function's move ctor as bug
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81017
// -- C++ --
/** 2227 * #brief %Function move constructor. 2228 * #param
__x A %function object rvalue with identical call signature. 2229 * 2230
* The newly-created %function contains the target of #a __x 2231 * (if
it has one). 2232 */ 2233
function(function&& __x) : _Function_base() { __x.swap(*this); }