C++11中使用智能指针容器的多态性



每当我定义VECTOR_OF_SHAPES时,我都希望编译以下代码,但它没有编译,我不明白为什么。

这个想法是使用一个智能指针容器来测试多态性。关于这个主题,我已经找到了类似的答案,它们指出了移动构造函数的需求;移动赋值运算符,这就是为什么我围绕RULE_OF_5编写了一些代码,但仍然出现了"使用已删除函数"的错误。

我尝试过使用g++、clang和cpp.sh的代码,它们都返回了几乎相同的输出。


#include <iostream>
#include <memory>
#include <vector>
#define inherits_from            : public
class Shape
{
public:
Shape() { std::cout << __FUNCTION__ << "()" << std::endl; }
#ifdef RULE_OF_5
Shape(const Shape&) {}
Shape(Shape&&) {}
Shape& operator=(const Shape&) { return *this; }
Shape& operator=(Shape&&) { return *this; }
#endif
virtual ~Shape() { std::cout << __FUNCTION__ << "()" << std::endl; }
virtual void Draw() = 0;
};
class Circle inherits_from Shape
{
public:
virtual void Draw() { std::cout << "Drawing a circle" << std::endl; }
};
class Triangle inherits_from Shape
{
public:
virtual void Draw() { std::cout << "Drawing a triangle" << std::endl; }
};
class Square inherits_from Shape
{
public:
virtual void Draw() { std::cout << "Drawing a square" << std::endl; }
};
void test()
{
auto shape0                   = std::make_unique<Circle>();
std::unique_ptr<Shape> shape1 = std::make_unique<Triangle>();
auto shapes                   = std::vector<std::unique_ptr<Shape>>();
#ifdef VECTOR_OF_SHAPES
auto shapes2                  = std::vector<std::unique_ptr<Shape>>
{
std::make_unique<Circle>()
}; // <- error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Shape; _Dp = std::default_delete<Shape>]’...
#endif
}
int main()
{
test();
return 0;
}

编译命令:

g++-8 -DVECTOR_OF_SHAPES -DRULE_OF_5 -ggdb -O0 -std=c++14 -Wall -Wextra -fPIC -pedantic  polymorphic-test.cpp -o polymorphic-test

完整的编译器输出:

In file included from /usr/include/c++/8/memory:64,
from polymorphic-test.cpp:3:
/usr/include/c++/8/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = std::unique_ptr<Shape>; _Args = {const std::unique_ptr<Shape, std::default_delete<Shape> >&}]’:
/usr/include/c++/8/bits/stl_uninitialized.h:83:18:   required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const std::unique_ptr<Shape>*; _ForwardIterator = std::unique_ptr<Shape>*; bool _TrivialValueTypes = false]’
/usr/include/c++/8/bits/stl_uninitialized.h:134:15:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const std::unique_ptr<Shape>*; _ForwardIterator = std::unique_ptr<Shape>*]’
/usr/include/c++/8/bits/stl_uninitialized.h:289:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = const std::unique_ptr<Shape>*; _ForwardIterator = std::unique_ptr<Shape>*; _Tp = std::unique_ptr<Shape>]’
/usr/include/c++/8/bits/stl_vector.h:1469:33:   required from ‘void std::vector<_Tp, _Alloc>::_M_range_initialize(_ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const std::unique_ptr<Shape>*; _Tp = std::unique_ptr<Shape>; _Alloc = std::allocator<std::unique_ptr<Shape> >]’
/usr/include/c++/8/bits/stl_vector.h:519:2:   required from ‘std::vector<_Tp, _Alloc>::vector(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = std::unique_ptr<Shape>; _Alloc = std::allocator<std::unique_ptr<Shape> >; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<std::unique_ptr<Shape> >]’
polymorphic-test.cpp:51:3:   required from here
/usr/include/c++/8/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 = Shape; _Dp = std::default_delete<Shape>]’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/8/memory:80,
from polymorphic-test.cpp:3:
/usr/include/c++/8/bits/unique_ptr.h:394:7: note: declared here
unique_ptr(const unique_ptr&) = delete;
^~~~~~~~~~

那么,有人能解释一下为什么每当我定义VECTOR_OF_SHAPE时,编译都会失败,以及如何修复代码吗?提前感谢

注意:我的答案是找到一种用初始化器列表构建向量的方法,而不是使用push_back((或template_back(

您的问题是调用vector构造函数,该构造函数采用初始值设定项列表。

unique_ptr只能移动。你不能复制它。

初始值设定项列表中的项被视为常量对象-基础类型为const Type[Size]

由于不能对const对象执行移动操作,所以编译器试图复制unique_ptr,但必须失败。unique_ptr的复制操作标记为已删除

作为变通方法,创建矢量,然后通过调用push_back:添加所有项目

std::vector<std::unique_ptr<Shape>> shapes2;
shapes2.push_back(std::make_unique<Circle>()); // move not copy happens here

编辑

你应该再问一个问题,而不是编辑当前的问题。

带有{}的版本无法工作,周期。

如果您不想使用push_back/emplace_back,请使用范围为(Begin,End):的过载

const int SIZE = 2;
std::unique_ptr<Circle> temp[2]{std::make_unique<Circle>(), std::make_unique<Circle>()};
auto shapes2 = std::vector<std::unique_ptr<Shape>>
(std::make_move_iterator(temp),std::make_move_iterator(temp+SIZE));

@rafix07:您对编译器错误的解释非常合理。

关于代码,我想粘贴一个几乎逐字逐句的你的建议版本,供下一个访问这个问题的人使用:

std::unique_ptr<Shape> temp[] =
{
std::make_unique<Circle>(),
std::make_unique<Triangle>(),
std::make_unique<Square>()
};
auto numberOfShapes = sizeof(temp)/sizeof(temp[0]);
auto shapes2 = std::vector<std::unique_ptr<Shape>>
(std::make_move_iterator(temp), std::make_move_iterator(temp + numberOfShapes));

所以,谢谢你的提示和完整的答案

最新更新