c ++当你在deque中使用push_back或push_front时会发生什么

时间:2017-12-20 10:44:13

标签: c++ stl push-back

我正在读这里: http://www.cplusplus.com/reference/deque/deque/push_back/

void push_back (const value_type& val);

val是

  

要复制(或移动)到新元素的值。

e.g。如果val是一个类的实例,在这种情况下它是否被复制并在其中被移动?这两种情况有什么区别?

您还可以解释以下每个add_val1,add_val2和add_val3中发生的不同情况吗?

#include <deque>

class Value
{
    int member1;
    int member2;
};


class ValuesContainer
{
private:
    std::deque<Value> m_vals;

public:

    void add_val1(const Value &val)
    {
        m_vals.push_back( val );
    }

    void add_val2(const Value val)
    {
        m_vals.push_back( val );
    }

    void add_val3(const Value &val)
    {
        m_vals.push_back( Value(val) );
    }

};

int main()
{
    return 0;
}

谢谢!

3 个答案:

答案 0 :(得分:1)

  

如果val是一个类的实例,在这种情况下它会被复制并且   它被移动了吗?这两种情况有什么区别?

如果某个值是某个类的实例,那么就比如说

class MyValue {};

MyValue originalValue;
MyValue copyAssignedValue = originalValue;

它总是被复制。发生这种情况是因为调用了复制赋值运算符。在类似的事情中,

MyValue copyConstructedValue(originalValue);

调用复制构造函数(如名称所示,复制内容)。

要理解为什么以及何时使用复制或移动构造函数,有必要了解这两个操作之间的区别:

复制对象就像普通的复制和粘贴一样:您现在拥有可以独立处理的同一对象的两个副本。移动对象就像剪切和粘贴:最后只有一个工作对象,旧的被删除。然而,它比复制要快得多,因为你不需要分配新的内存。

要移动对象,您可以执行一些操作。例如,您可以创建一个编译器知道您只需要在移动构造函数中使用的对象。

MyValue moveConstructedValue(MyValue());

为了清楚起见,这就是移动构造函数的样子:

MyValue::MyValue(MyValue&& other);

注意双&&,表示右值引用(单&现在称为左值引用)。

或者你可以表明你想要显式使用移动构造函数(注意,originValue对象将被重置为默认值):

MyValue valueToBeMovedTo(std::move(originalValue));

回答你的第二个问题,你的哪个函数使用了一个移动操作:实际上,它们都没有将val“移动”到m_vals中,因为编译器不知道你以后是否想要使用它。您可以使用新的右值参考来移动:

void add_valMoving(const Value &&val)
{
   m_vals.push_back( val );
}

要100%更正,add_val3使用移动构造函数,但不直接在val对象上:它首先调用Value的复制构造函数并将val复制到新对象中,然后使用移动构造函数将新对象移动到deque。

修改

要在移动对象时更清楚“默认值”,移动构造函数可以是:

class MyValue 
{
public:
    MyValue(MyValue&& other)
    {
       this->member = other.member;
       other.member = 0;
    }

private:
    int member;
}

但是,您永远不会知道移动后原始对象的值。

答案 1 :(得分:1)

该引用让您感到困惑,因为默认情况下它只显示 复制push_back,并且仍在谈论移动。

从C ++ 11开始,有两个 push_back s

    始终复制
  • void push_back( const T& value );
  • 始终移动的
  • void push_back( T&& value );

如果你推回的值有名称,或明确是T&,那么它将使用第一个,否则第二个

void add_val1(const Value &val)
{
    m_vals.push_back( val ); // copy
}

void add_val2(const Value val)
{
    m_vals.push_back( val ); // copy
}

void add_val3(const Value &val)
{
    m_vals.push_back( Value(val) ); // move the temporary that is a copy of val
}

extern Value make_value_somehow() 

void add_val4()
{
    m_vals.push_back( make_value_somehow() ); // move
}

extern Value& find_value_somehow() 

void add_val5()
{
    m_vals.push_back( find_value_somehow() ); // copy
}

void add_val6(Value val)
{
    m_vals.push_back( val ); // copy
}

void add_val7(Value val)
{
    m_vals.push_back( std::move(val) ); // move
}

void add_val8(const Value val)
{
    // m_vals.push_back( std::move(val) ); // ill-formed, can't modify val
}

void add_val9(Value & val)
{
    m_vals.push_back( std::move(val) ); // move, which will confuse people
}

答案 2 :(得分:0)

  

要复制(或移动)到新元素的值。

这取决于push_back中使用的重载(请参阅this,在我看来,更好的参考页)。

add_val1需要参考和push_back副本 add_val2取值(因此函数会复制它),而不是push_back再次复制。{ add_val3需要引用,您可以调用副本,但由于Value(val)是r值,因此临时值会移动push_back