将用unique_ptr的对象推入C 中的向量



我有一个简单的类结构,它们具有一个带有状态向量的离散模拟的模拟,每个模拟都包含许多过渡,作为智能指针的向量。我已经使用智能指针来保持过渡,就像我的完整应用一样,我需要多态性。

#include <vector>
#include <memory>
class Transition {
    public:
        Transition() {}
};

class State {
    public:
        State(int num) : num(num), transitions() {}
        void add_transition(std::unique_ptr<Transition> trans) {
            transitions.push_back(std::move(trans));
        }
    private:
        int num;
        std::vector<std::unique_ptr<Transition>> transitions;
};

int main() {
    std::vector<State> states;
    for (int i = 0; i < 10; i++) {
        State nstate = State(i);
        for (int j = 0; j < 2; j++) {
            nstate.add_transition(std::move(std::unique_ptr<Transition>(new Transition())));
        }
        // This line causes compiler errors
        states.push_back(nstate);
    }
}

在向向量添加新状态对象时,我会发现编译器错误:

Error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Transition; _Dp = std::default_delete<Transition>]’
 { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }

我想这是由于向量制作状态对象的副本,该副本也试图制作不允许的 unique_ptrs矢量的副本。我已经看到emplace_back没有像push_back这样的副本,但我仍然遇到相同的错误。

将状态对象直接添加到向量中有效,但是我希望避免使用此解决方法,就像我在实际代码中一样,我可以与状态对象进行更多工作,而不仅仅是添加过渡,也不想继续访问向量。

int main() {
    std::vector<State> states;
    for (int i = 0; i < 10; i++) {
        states.push_back(State(i));
        for (int j = 0; j < 2; j++) {
            states[i].add_transition(std::move(std::unique_ptr<Transition>(new Transition())));
        }
    }
}

State是不可复制的,而是可移动的;但是对于states.push_back(nstate);nstate是一个LVALUE(作为命名变量(,无法从中移动。然后尝试执行副本,但不允许进行。

要解决它,您可以使用std::move(将其转换为rvalue(:

states.push_back(std::move(nstate));

live


请注意,移动操作后,nstate的数据成员(包括向量及其内容(也将被移动。

您需要做出所有权决定。

new的所有者(或所有者(分配的对象负责确保其在其生命周期结束时被删除。

如果vector<>拥有对象,则std::move()std::unique_ptr<>纳入vector,然后继续通过" RAW"指针访问对象,但如果vector被破坏或std::unique_ptr被擦除/RESET/RESET。

如果vector<>不拥有该对象,则在破坏std::unique_ptr时会识别其无效(除非您进行干预(。

如果存在复杂的关系,请考虑std::shared_ptr<>,该CC_19将允许多个对象共享所有权,但请确保无法进行循环引用。

除此之外

一项肤浅的检查表明,"状态"可能拥有其Transition S,因为总的来说,在国家存在的同时,它们在存在时就会有意义,而在不存在的情况下就停止变得有意义。因此,继续使用vector<std::unique_ptr<> >并访问State和/或Transition作为指针。

如果在您的情况下不起作用,则可能需要一个拥有所有状态和所有过渡的"拟合"上下文对象被摧毁。

// This line causes compiler errors
states.push_back(nstate);

nstate对象是State类的实例。State类包含两个数据成员:int(可复制(和unique_ptr s的vector,即可移动但不可复制(由于unique_ptr是可移动的,但不可复制(。因此,整个State类都是可移动的,但不可复制。因此,您必须std::move nstate对象到states向量:

states.push_back(std::move(nstate));

如果您想要 copy 语义,则应使用 shared_ptr s的向量(参考计数 smart smart指针,并且是 as em 可复制可移动(。


我还将对您的State类代码进行一些修改:

class State {
    public:
        State(int num) : num(num), transitions() {}

在这里,您应该标记构造函数explicit,以避免使用int隐式转换。此外,std::vector数据成员是自动初始化的,无需在此处使用transitions()

此外,考虑到这条代码:

states[i].add_transition(std::move(std::unique_ptr<Transition>(new Transition())));

您应该使用std::make_unique(在C 14中引入(,而不是用明确调用new返回的RAW指针构造std::unique_ptr

您应该避免使用push_back并使用emplace_back代替创建项目。

constexpr ::std::int32_t const states_count{10};
constexpr ::std::int32_t const transitions_per_state_count{2};
::std::vector< State > states;
states.reserve(states_count);
for(::std::int32_t state_index{}; states_count != state_index; ++state_index)
{
    states.emplace_back(state_index); // new state is added without copying or moving anything
    auto & nstate{states.back()};
    for(::std::int32_t transition_index{}; transitions_per_state_count != transition_index; ++transition_index)
    {
        nstate.add_transition(::std::unique_ptr< Transition >{new Transition{}});
    }
}

您需要为您的State实现移动构造函数,并致电std::move以移动对象

class State {
public:
    // default if you just want it to move the members one by one
    State(State&& s) = default;
};
states.push_back(std::move(nstate));

您将std::unique_ptr<Transition>传递给按值函数,该值应在void add_transition(std::unique_ptr<Transition> trans)中创建本地副本。

如果您将通过参考std::unique_ptr<Transition>& trans传递值,则不需要任何std::move add_transition函数。

您也可能需要使用std::make_unique<Transition>()而不是std::uniqye_ptr<Transition>(new Transition())

new关键字的封装使您的代码更清晰,并命令创建内存泄漏的概率。

相关内容

  • 没有找到相关文章

最新更新