【问题标题】:std::vector<Foo> when some members of Foo are referencesstd::vector<Foo> 当 Foo 的某些成员是引用时
【发布时间】:2013-11-17 02:11:01
【问题描述】:

我通常更喜欢使用引用而不是指针,我认为它使语法更清晰。在这种情况下,我有一个类:

class Foo
{
public:
    Foo(Bar & bar) : bar_(bar) {}

private:
    Bar & bar_;
};

operator=() 被编译器隐式删除,因为一旦设置了引用,它就无法更改(我可以在技术上定义我自己的不会更改 bar_,但这不是必需的行为,所以如果我尝试分配一个 foo,我宁愿编译器抱怨)。

我需要的是std::vector&lt;Foo&gt; v;。这在 C++11 之前是不可能的,因为模板参数必须是 CopyAssignable。事实上,当我调用v.push_back(Foo(bar)); 时,编译器会抱怨。但我觉得从 C++11 和 Move 语义开始就有可能。

我的问题是:是否有使用 C++11 的解决方法可以构建这样的向量,或者我是否陷入这种情况并且无法使用指针而不是引用?如果有解决方法,我非常感谢代码 sn-p,因为我不熟悉移动语义。

【问题讨论】:

  • 我认为 emplace back 是你要找的
  • Foo(const Foo &amp;&amp; foo) : bar_(foo.bar_) {} 不能解决这个问题吗?
  • 我确信,根据您的类如何定义其构造函数,push_back 可以使用隐式移动生成正常工作。你的例子对我来说编译得很好吗?
  • 您需要std::optionalboost::optional。它们都具有指针的大小。 boost::optional&lt; T &amp; &gt;/boost::optional&lt; T const &amp; &gt; 具有所需的语义。

标签: c++ c++11 stdvector move-semantics


【解决方案1】:

瞧,emplace_back 能够完成这项工作是因为完美的转发。

#include <vector>                                                                  

class Bar{};                                                                       
class Foo                                                                          
{                                                                                  
public:                                                                            
    Foo(Bar & bar) : bar_(bar) {}                                                  

private:                                                                           
    Bar & bar_;                                                                    
};                                                                                 
using namespace std;                                                               
int main() {                                                                       
    vector<Foo> v;                                                                 
    Bar bar;
    v.emplace_back(bar);                                                     
} 

您也可以将引用本身存储在一个容器中,使用 std::reference_wrapper 就像std::vector&lt;std::reference_wrapper&lt;int&gt;&gt; v 一样

【讨论】:

  • @Boris 你能发布一个无法编译的完整示例吗,因为我实际上意识到我的示例 push_back 也可以编译
  • @Boris 抱歉,我会看一下,但可能很难找出问题所在,因为我没有那个编译器
  • 您应该将 Foo 的构造函数的参数直接传递给 emplace_back,否则您将创建一个不必要的临时对象并调用复制/移动构造函数。
  • @Trillian 你说的是第一个 emplace_back 吧,我会直接删除它
  • @aaronman 应该是 v.emplace_back(bar) 而不是 v.emplace_back(Foo(bar))emplace 旨在为正在创建的类型获取构造函数参数,而不是在该类型的对象上。 @Boris - 是的,gcc 4.6 远远落后于 c++11 支持。 4.8 更好。
【解决方案2】:

使用v.emplace_back(bar) 代替push_back。它将在vector 为其分配的内存中构造一个Foo,因此不需要复制。只需传递emplace_back 的参数即可构造Foo

【讨论】:

  • +1 用于提供正确的语法,我接受了 aaronman 的代码 sn-p :)
【解决方案3】:

容器的模板参数不一定是CopyAssignable,它取决于你对容器执行的操作,如果你真的使用需要CopyAssignable或MoveAssignable的操作,你不能随意使用引用(即使带有移动语义)。但如果你只使用其他操作(见标准),那就没问题了。有些操作只需要 CopyInsertable、MoveInstable 和/或 EmplaceConstructible。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-23
    • 2011-12-20
    • 2014-01-11
    • 1970-01-01
    • 2011-04-26
    • 2011-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多