处理 stl 容器中的智能指针
我有一个 Foo
类,它有一个指向 Shape
派生类的智能指针向量。
我正在尝试实现 at(index)
成员函数。以下是我直观地要做的事情:
Foo<float> myfoo;
std::unique_ptr<Shape<float>> shape_ptr = myfoo.at(i);
shape_ptr->doSomething(param1, param2, ...);
定义 at(index)
函数时,我收到编译器错误消息。请注意,移动构造函数已定义,并且 Shape 基类是抽象的。下面,我给出一些代码用于说明目的。
此外,我最近在网上发现了一个关于如何使用 std::move 重载赋值运算符的示例。我通常遵循复制交换习惯用法。重载上述运算符的两种方法中哪一种对我的情况有意义?下面,我还说明了该函数的定义。
template < typename T >
class Foo{
public:
Foo();
Foo( Foo && );
~Foo();
void swap(Foo<T> &);
//Foo<T> & operator =( Foo<T> );
Foo<T> & operator =( Foo<T> && );
std::unique_ptr<Shape<T> > at ( int ) const; // error here!
int size() const;
private:
std::vector< std::unique_ptr<Shape<T> > > m_Bank;
};
template < typename T >
Foo<T>::Foo( Foo && other)
:m_Bank(std::move(other.m_Bank))
{
}
/*template < typename T >
void Filterbank<T>::swap(Filterbank<T> & refBank ){
using std::swap;
swap(m_Bank, refBank.m_Bank);
}
template < typename T >
Foo<T> & Filterbank<T>::operator =( Foo<T> bank ){
bank.swap(*this);
return (*this);
}*/
template < typename T >
Foo<T> & Foo<T>::operator =( Foo<T> && bank ){
//bank.swap(*this);
m_Bank = std::move(bank.m_Bank);
return (*this);
}
template < typename T >
std::unique_ptr<Shape<T> > Foo<T>::at( int index ) const{
return m_Bank[index]; // Error here! => error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
使用 Boost 的指针容器而不是标准容器与 unique_ptr。它们是为这种用途而设计的。
Use Boost's pointer containers instead of a standard container with unique_ptr. They're designed for this kind of usage.
问题 1:如何使用
Foo::at( int ) const
以便您可以:无需将所有权转移出
vector>>
>。A1:
Foo::at( int ) const
应该返回一个const std::unique_ptr; >&
:现在您可以取消引用 const
unique_ptr
并调用它们想要的Shape
的任何成员(const 或非 const)。如果他们不小心尝试复制unique_ptr
(这会将所有权转移出Foo
),他们将收到编译时错误。此解决方案比返回对
unique_ptr
的非常量引用更好,因为它捕获了Foo
中意外的所有权转移。但是,如果您希望允许通过at
从Foo
转移所有权,那么非常量引用会更合适。Q2:此外,我最近在网上发现了一个关于如何使用 std::move 重载赋值运算符的示例。我通常遵循复制交换习惯用法。重载上述运算符的两种方法中哪一种对我的情况有意义?
A2:我不确定
~Foo()
的作用。如果它没有做任何事情,您可以将其删除,然后(假设完全符合 C++11)您将自动获得正确且最佳的移动构造函数和移动赋值运算符(以及正确的删除复制语义)。如果您无法删除
~Foo()
(因为它做了一些重要的事情),或者您的编译器尚未实现自动移动生成,您可以显式提供它们,就像您在问题中所做的那样。您的移动构造函数是正确的:移动构造成员。
您的移动分配应该类似(如果
~Foo()
是隐式的,则会自动生成): 移动分配成员:您的
Foo
设计适合于 < code>Swappable 也是如此,而且提供起来总是好的:如果没有这个显式的
swap
,您的Foo
仍然是Swappable
使用 < code>Foo 的移动构造函数和移动赋值。然而,这种显式交换的速度大约是隐式交换的两倍。上述建议都是为了获得
Foo
的最高性能。如果需要,您可以在移动分配中使用复制交换习惯用法。它会是正确的并且稍微慢一些。不过,如果您确实小心的话,请不要通过swap
调用移动赋值和移动赋值调用swap
来获得无限递归! :-) 事实上,这个陷阱只是干净(且最佳)分离交换
和移动分配的另一个原因。更新
假设
Shape
看起来像这个,这是一种方法为Foo
编写移动构造函数、移动赋值、复制构造函数和复制赋值运算符,假设Foo
有一个数据成员:...
如果您的编译器支持默认的移动成员 方式实现:
,同样的事情可以通过以下 移动构造函数和移动赋值运算符。
上述内容确保在任何时候每个
Shape
仅由一个智能指针/向量/Foo 拥有。如果您希望多个Foo
共享Shape
的所有权,那么您可以将其作为数据成员:并且您可以默认所有移动构造函数、移动赋值、复制构造函数和复制赋值。
Q1: What to do with
Foo::at( int ) const
such that you can:without transferring ownership out of the
vector<unique_ptr<Shape<T>>>
.A1:
Foo::at( int ) const
should return aconst std::unique_ptr<Shape<T> >&
:Now your can dereference the const
unique_ptr
and call any member ofShape
they want (const or non-const). If they accidentally try to copy theunique_ptr
, (which would transfer ownership out ofFoo
) they will get a compile time error.This solution is better than returning a non-const reference to
unique_ptr
as it catches accidental ownership transfers out ofFoo
. However if you want to allow ownership transfers out ofFoo
viaat
, then a non-const reference would be more appropriate.Q2: Furthermore, I found recently on the web an example on how to overload the assignment operator using std::move. I usually follow the Copy-Swap idiom. Which of those two ways for overloading the mentioned operator makes sense for my case?
A2: I'm not sure what
~Foo()
does. If it doesn't do anything, you could remove it, and then (assuming fully conforming C++11) you would automatically get correct and optimal move constructor and move assignment operator (and the proper deleted copy semantics).If you can't remove
~Foo()
(because it does something important), or if your compiler does not yet implement automatic move generation, you can supply them explicitly, as you have done in your question.Your move constructor is spot on: Move construct the member.
Your move assignment should be similar (and is what would be automatically generated if
~Foo()
is implicit): Move assign the member:Your
Foo
design lends itself to beingSwappable
too, and that is always good to supply:Without this explicit
swap
, yourFoo
is stillSwappable
usingFoo
's move constructor and move assignment. However this explicitswap
is roughly twice as fast as the implicit one.The above advice is all aimed at getting the very highest performance out of
Foo
. You can use the Copy-Swap idiom in your move assignment if you want. It will be correct and slightly slower. Though if you do be careful that you don't get infinite recursion withswap
calling move assignment and move assignment callingswap
! :-) Indeed, that gotcha is just another reason to cleanly (and optimally) separateswap
and move assignment.Update
Assuming
Shape
looks like this, here is one way to code the move constructor, move assignment, copy constructor and copy assignment operators forFoo
, assumingFoo
has a single data member:...
If your compiler supports defaulted move members, the same thing could be achieved with:
for the move constructor and move assignment operator.
The above ensures that at all times each
Shape
is owned by only one smart pointer/vector/Foo. If you would rather that multipleFoo
s share ownership ofShape
s, then you can have as your data member:And you can default all of move constructor, move assignment, copy constructor and copy assignment.
我认为你应该在这里使用 shared_ptr 。
只有一个 unique_ptr 可以拥有共享资源。如果您能够执行您想要的操作,即按值返回一个 unique_ptr,那么向量中的那个将被销毁,这可能是您不想要的。
I think you should be using shared_ptr here instead.
Only one unique_ptr can own the shared resource. If you are able to do what you intend ie return a unique_ptr by value then the one in the vector will be destroyed which is probably what you don't want.
看来你应该在这里返回一个引用:
It seems like you should just be returning a reference here: