【问题标题】:Moving vector from class, return && or move into temporary?从类中移动向量,返回 && 或移动到临时?
【发布时间】:2014-03-11 10:48:14
【问题描述】:
class EntityFactory
{
public:
    EntityFactory(tinyxml2::XMLElement * pEntitiesNode);
    ~EntityFactory();

    std::vector< std::unique_ptr<Entity> > && TakeEntities();

protected:
    std::vector< std::unique_ptr<Entity> > mEntities;
};

当我调用 TakeEntity 时,我想将 mEntities 向量移到此类之外。

我应该返回我移入的临时变量还是返回 &&?

std::vector< std::unique_ptr<Entity> > && EntityFactory::TakeEntities()
    {
    return std::move(mEntities);
    }

//or
std::vector< std::unique_ptr<Entity> > EntityFactory::TakeEntities()
    {
    return std::move(mEntities);
    }

我想要的最终结果是我可以从其他地方调用这个函数,并将场向量移动到调用点附近的一个变量中。

【问题讨论】:

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


    【解决方案1】:

    正确的方法大概是按值返回并且只有在实例是可移动的情况下才这样做:

    class Foo
    {
        std::unique_ptr<Bar> bar_;
    
    public:
        std::unique_ptr<Bar> get_bar() &&
        {
            return std::move(bar_);
        }
    };
    

    这样,只有在整个实例本身即将到期时,您才能从成员中移出。一般来说,没有必要返回一个右值引用,因为这给你带来的收益很少,而且通常会带来不安全的巨大代价。例如,假设你有Foo f();,那么考虑:

    auto && p = f().get_bar();
    

    如果按值返回,这是安全的,但如果按引用返回,则将是一个悬空引用。

    【讨论】:

    • 这个语法叫什么名字? std::unique_ptr get_bar() &&
    • @EddieV223:标准将其称为 ref-qualifier,因此您可以说“get_bar 是右值限定的”。
    【解决方案2】:

    如果您禁用编译器copy elision,请使用第一个,因为第二个会生成额外的临时变量,这会降低性能。

    如果您没有禁用copy/move elision,它们很可能是相同的(性能)。

    【讨论】:

      【解决方案3】:

      你不应该返回一个右值引用并且可能定义一个合适的实体:

      #include <iostream>
      #include <vector>
      
      struct Entity {
          int value;
          Entity() {
              static int n;
              value = ++n;
          }
      
          Entity(Entity&&) = default;
          Entity& operator = (Entity&&) = default;
      
          Entity(const Entity&) = delete;
          Entity& operator = (const Entity&) = delete;
      };
      
      class EntityFactory
      {
          public:
          EntityFactory() {};
      
          void insert(Entity&& entity) {
              return mEntities.push_back(std::move(entity));
          }
      
          std::vector<Entity> Entities() {
              return std::move(mEntities);
          }
      
          protected:
          std::vector<Entity> mEntities;
      };
      
      int main() {
          EntityFactory factory;
          factory.insert(Entity());
          factory.insert(Entity());
          factory.insert(Entity());
          std::vector<Entity> entities = factory.Entities();
          for(const auto& e: entities) {
              std::cout << e.value;
          }
          std::cout << std::endl;
          if(factory.Entities().empty())
              std::cout << "Empty factory\n";
      }
      

      目标(获得函数调用结果的值)将是复制省略值或右值构造值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-04
        • 1970-01-01
        • 2022-12-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多