简体   繁体   English

我可以在 std::move 之后重复使用像 std::vector 这样的复杂 class 吗?

[英]Can I re-use a complex class like std::vector after std::move?

I'm creating a game, and trying to learn move semantics/r-value references.我正在创建一个游戏,并尝试学习移动语义/r 值引用。

I have a class that adds an Event into a vector every frame.我有一个 class 每帧将一个Event添加到一个vector中。

After 60 frames, I want to move all the accumulated events into a new class (called Step ), which will be stored in another vector . 60 帧后,我想将所有累积的事件移动到一个新的 class (称为Step )中,它将存储在另一个vector中。

I want this process to repeat, so after the Event vector is moved, it should reset to being empty.我希望重复此过程,因此在移动Event向量后,它应该重置为空。

#include <vector>

class Event
{
    ...
}

class Step
{
    std::vector<Event> Events;

    Step(std::vector<Event>&& InEvents) : Events {InEvents} {}
}

class EventAccumulator
{
    std::vector<Event> Events;
    std::vector<Step> Steps;

    void Update(int FrameCount)
    {
        Events.push_back(Event());

        if (FrameCount % 60 == 0)
        {
            // Move accumulated events into a new Step.
            Step NewStep = Step(std::move(Events));
            Steps.push_back(NewStep);

            // Reset Events so that we can accumulate future events.
            Events = std::vector<Event>();
        }
    }
}

// Game Loop
int GlobalFrameCount = 0;
EventAccumulator eventAccumulator{};
while (true)
{
    eventAccumulator.Update(GlobalFrameCount++);
}

It's my understanding that the line Step NewStep = Step(std::move(Events));我的理解是Step NewStep = Step(std::move(Events)); will 'give' Events to NewStep (ie the vector is not copied).将“给” EventsNewStep (即不复制向量)。 Please correct me if I'm wrong on this.如果我在这方面错了,请纠正我。

I want the line Events = std::vector();我想要行Events = std::vector(); to cause EventAccumulator.Events to be reset to an empty vector, but I do NOT want NewStep.Events to be reset.导致EventAccumulator.Events被重置为空向量,但我不希望NewStep.Events被重置。

My question is, will this code do what I want?我的问题是,这段代码会做我想要的吗?

Additionally, how can you tell whether this will work/not work for all complex classes like std::vector ?此外,您如何判断这是否适用于所有复杂类,如std::vector I think it's determined by the assignment operator overload of the class, but I'm confused on this.我认为这是由 class 的赋值运算符重载决定的,但我对此感到困惑。

Your code always copy the Events vector, so Events = std::vector();您的代码总是复制Events向量,所以Events = std::vector(); will simply erase the copied-from elements.只会删除复制的元素。

Why does it copy and not a move?为什么它复制而不是移动? Let's take a look at the Step constructor:让我们看一下Step构造函数:

//                         that's a copy -----v
Step(std::vector<Event>&& InEvents) : Events {InEvents} {}

Indeed, the expression (InEvents) is an lvalue, because it has a name.事实上,表达式(InEvents)是一个左值,因为它有一个名称。 You must cast it to an rvalue using std::move :您必须使用std::move将其转换为右值:

Step(std::vector<Event>&& InEvents) : Events {std::move(InEvents)} {}

When taking parameters by && , remember that it's a maybe move since its simply a reference like any other, and you must move it explicitly.通过&&获取参数时,请记住这是一个可能的移动,因为它只是一个引用,就像其他任何引用一样,您必须明确移动它。


This line won't compile:此行不会编译:

Events = std::vector();

Maybe you meant this:也许你的意思是:

Events = {};

This will indeed allow you to reuse your vector.这确实可以让你重用你的向量。 It will be reset in a way that leads to a determinate state.它将以导致确定的 state 的方式重置。

I want the line Events = std::vector();我想要行Events = std::vector(); to cause EventAccumulator.Events to be reset to an empty vector, but I do NOT want NewStep.Events to be reset.导致EventAccumulator.Events被重置为空向量,但我不希望NewStep.Events被重置。

My question is, will this code do what I want?我的问题是,这段代码会做我想要的吗?

C++ has value semantics. C++ 具有值语义。 Unless NewStep contains a std::vector<Event>& you cannot affect a variable somewhere else.除非NewStep包含std::vector<Event>&你不能影响其他地方的变量。 Also you move construct the vector in NewStep .您还可以在NewStep中移动构造向量。 That should tell you something: You constructed a new vector.这应该告诉你一些事情:你构建了一个新的向量。 No matter how you mutate the old vector, it cannot affect a distinct vector.无论您如何改变旧向量,它都不会影响不同的向量。 This code will do what you want, if you correct the Step constructor.如果您更正Step构造函数,此代码将执行您想要的操作。


Keep in mind that if you want to avoid many allocation, you will have to call reserve like this:请记住,如果您想避免多次分配,您将不得不像这样调用reserve

Events.reserve(60);

As I added in the comments, constructor are a special case for move semantics: taking by value and move it adds very little costs and most likely elided.正如我在评论中添加的那样,构造函数是移动语义的一种特殊情况:按值获取并移动它会增加很少的成本,并且很可能会被省略。 Here's what I meant by that:这就是我的意思:

Step(std::vector<Event> InEvents) : Events {std::move(InEvents)} {}

If you pass by copy, then it will copy into InEvents and move it.如果您通过副本传递,那么它将复制到InEvents并移动它。 If you pass by move, it calls the move constructor two times, no copy.如果你通过 move 传递,它会调用 move 构造函数两次,没有副本。

Since the cost of calling the move constructor is negligible, it saves you from writing an overload.由于调用移动构造函数的成本可以忽略不计,它使您免于编写重载。

It only works in constructors since we cannot reuse capacity anyway .它只适用于构造函数,因为我们无论如何都不能重用容量 This is not true for the assignment or a setter function.这不适用于赋值或设置器 function。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM