【问题标题】:Returning an rvalue reference from a nonlocal从非本地返回右值引用
【发布时间】:2013-01-14 21:53:33
【问题描述】:

我有一个查询内部状态对象的类:

class State {...}; //Has a copy and move constructor
class Processor
{
private:
    std::unique_ptr<State> state;

public:
    void process(...)
    {
        State newState;
        ... //create this new state
        state.reset(new State(newState));
    }

    State getState()
    {
        return std::move(*state.release());
    }
};

std::move 的用法合适吗?我可以保证每次调用process 只会调用一次getState,但是由于这个特定系统的设计,我不能只从process 返回newState。 Stack Overflow 和其他地方的许多其他答案都说最好只返回对象,因为编译器无论如何都会移动它或 RVO 它,但这些都是在返回的对象是函数本地的情况下.

我不一定需要将状态对象放在 unique_ptr 后面,但这似乎是管理新状态对象的最简单方法。我的实际实现最后有一个指针直接转移到 unique_ptr。

【问题讨论】:

  • shared_ptr 不是更好的选择吗?
  • 我想让 getState 函数只返回对象。我不想将实现的指针性暴露给外界。
  • 你知道这个泄漏,是吗?
  • 为什么不公开参考?跟正常人一样? :)
  • 我很好奇这段代码打算解决的实际问题?

标签: c++ c++11 move-semantics unique-ptr rvalue-reference


【解决方案1】:

原来的演示代码有问题——unique_ptr 从不释放指针。答案是将移到局部函数空间,然后正常返回。

class State {...}; //Has a copy and move constructor
class Processor
{
private:
    std::unique_ptr<State> state;

public:
    void process(...)
    {
        State* newState;
        ... //newState is allocated on the heap somehow
        state.reset(newState);
    }

    State getState()
    {
        State _state(std::move(*state));
        //Optionally: state.reset();
        return _state;
    }
};

【讨论】:

    【解决方案2】:

    只返回状态有什么问题

    struct state {};
    class processor {
    public:
      void process() {
        state_ = State();
      }
    
      state get_state() {
        return std::move(state_);
      }
    
    private:
      state state_;
    };
    

    这将在构造处理器时默认构造 state_ 但 您可以使用 optional 包装器来防止这种情况。你还是要 保证get_state 只在process 之后被调用,这 真是烂透了。

    【讨论】:

    • 仅查看此示例代码时,关于get_state()process(...) 的保证很糟糕,但在我正在处理的实际项目中是有道理的。我将状态包装在 unique_ptr 中,因为如果没有结果状态,process(...) 函数可能会将其设置为 nullptr
    • @Lucretiel 在这种情况下get_state 可能会返回什么?显然,您不需要指针,而是需要 boost::optional(或类似的东西),然后返回对 get_state 中所述可选的引用。
    【解决方案3】:

    您可以只返回类型为std::unique_ptr&lt;State&gt;state,它会完美地与std::move(state) 一起移动。在这种情况下,您可以在按值返回时复制整个 state 对象。如果调用者没有捕获到 state 对象,它将被自动销毁。对于复杂的堆分配对象,这是一种非常有效的方法。但要小心,通过移动state,您正在清除Processor 对象的状态。所以,getState 在这种情况下并不是一个最佳名称,它应该类似于 fetchStatepopState

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-15
      • 1970-01-01
      • 1970-01-01
      • 2020-09-21
      • 1970-01-01
      • 2020-07-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多