【问题标题】:What std::vector in C++ really is? [duplicate]C++ 中的 std::vector 到底是什么? [复制]
【发布时间】:2014-08-10 06:36:30
【问题描述】:

到目前为止,我还没有发现,我完全不知道 std::vector 的性质。

让我解释一下:

Vector 是可增长的,对吧?这意味着,在它内部必须以某种方式动态分配/重新分配内存。像这样的:

class vector {
private:
    int *data;
};

好的。但是这样的定义意味着如果我们通过引用或值将 std::vector 传递给另一个函数——这两种类型的参数传递之间没有区别,并且两个函数都能够修改数据(除非向量是作为 const 传递)。

但是!我尝试了以下方法,但我的想法失败了:

void try_to_modify(vector<int> v) {
    v[2] = 53;
}

int main() {
    vector<int> v(3);
    v[2] = 142;
    try_to_modify(v);
    cout << v[2] << '\n';    // output is: 142

    return 0;
}

那么真相在哪里? std::vector 到底是什么?

谢谢。

【问题讨论】:

  • 看一个实现。例如,libc++。它会像人们期望的那样进行深层复制。
  • 你忘记了它有一个复制数据的复制构造函数
  • @TheParamagneticCroissant 呃,不。这种行为实际上是有道理的。这不是一个“怪癖”。这就是值类型应该的工作方式。此外,这与 C 中的行为完全相同。
  • @TheParamagneticCroissant,当你通过值传递时,实际上并没有通过引用传递。对我来说似乎很简单。您只需要知道 C++ 具有值语义。
  • 与C完全相同的行为。std::vector&lt;int&gt;是一个值,他传递了一个值,它被复制并且函数有它自己的独立副本。它不是指针或引用类型。这是一个值。你对std::vector&lt;int&gt;int* 的心智模型非常、非常破碎和错误。

标签: c++ vector stl


【解决方案1】:

std::vector 是一个容器,它在内部管理其内存并提供自定义的复制构造函数。在此复制构造函数中,分配了新内存并复制了现有数据,这使其成为一项昂贵的操作。如果你想传递一个向量而不复制包含的数据,你可以通过 const 引用传递,例如,const std::vector&lt;int&gt;&amp;

让我们看看如何实现一个基本的容器,比如 std::vector。

template <typename T>
class MyVector
{
public:
    MyVector (int size)
    : data_ (new T[size])
    , size_ (size)
    {}

    ~MyVector ()
    {
        delete [] data_;
    }

 private:
    T* data_ = nullptr;
    int size_ = 0;
};

如果我们复制这样一个对象,我们会遇到两个问题。首先,正如您所注意到的,内存将指向同一个位置。其次,我们将有两个析构函数来破坏相同的内存,从而导致双重释放。所以,让我们添加一个复制构造函数,它会在复制时被调用。

MyVector (const MyVector& other)
: size_ (other.size_)
{
    data_ = new T[size_];
    std::copy (other.data_, other.data_ + size_, data_);
}

MyVector& operator= (const MyVector& other)
{
    // allocate and copy here to allow for self-assignment
    auto newData = new T[other.size_];
    std::copy (other.data_, other.data_ + size_, newData);

    delete [] data_;

    size_  = other.size_;
    data_ = newData;

    return *this;
}

这就是std::vector 在内部的工作方式。

【讨论】:

  • 您不应该在复制 ctor 中省略删除吗?它永远不会发生?
  • 修复了自分配。是的,不需要复制 dtor 中的删除,谢谢!
  • 这是实现复制分配的糟糕方法。它应该是复制和交换。
  • @user3791372 忽略混乱的语法,“C++ 中的 std::vector 到底是什么?”好像在问一个vector是怎么实现的。
  • @user3791372 OP 显然想知道为什么std::vector 没有显示他们想象的实现会产生的引用语义。
【解决方案2】:

这不是向量的问题,而是按值传递和按引用传递参数的问题。

void try_to_modify (vector&lt;int&gt; vec) 将原始向量的副本发送给函数,函数对副本进行操作。制作副本时,向量将复制数据。即指向新数据的新指针。

但是,如果您将函数定义为:void try_to_modify(vector&lt;int&gt; &amp; vec),那么它将向函数发送确切的向量,并且您的函数将对其进行操作。

通过引用传递对象的速度要快得多,而且通常更可取,除非您特别需要副本。

【讨论】:

  • 通过引用传递不一定快得多。它可能是,但如果你需要一个副本,你需要一个副本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-20
  • 2021-09-17
  • 2018-07-24
  • 1970-01-01
  • 2016-03-30
  • 1970-01-01
  • 2011-02-23
相关资源
最近更新 更多