【问题标题】:How to randomly assign to vector in C++?如何在 C++ 中随机分配给向量?
【发布时间】:2012-11-13 19:06:44
【问题描述】:

我是 C++ 新手,经常被告知使用 std::vector 而不是 new[]

我正在尝试实现此功能,因为我知道向量的大小并希望随机(而不是按顺序)分配给它。

但是,当运行它时,我的程序终止并且没有错误输出,所以我很难过。

vector<string> v1;
v1.resize(2);
v1.insert(v1.begin() + 1, "world");
v1.insert(v1.begin() + 0, "world");

cout << v1.at(1) << endl;

【问题讨论】:

  • "arrays (just pointers)" 你这是什么意思?数组绝对不是“只是指针”。
  • @LightnessRacesinOrbit 我的意思是不要使用矢量<:mat>,而是使用 cv::Mat*
  • 所以您的意思是指向动态分配的内存块的指针,该内存块大到足以容纳N 连续的cv::Mat 对象。

标签: c++ arrays vector


【解决方案1】:

别放弃,比那更容易

vector<string> v1(2);
v1[1] = "world";
v1[0] = "world";

cout << v1[1] << endl;

vector::insert 用于当您想要将项目添加到向量时,而不是当您想要替换已经存在的项目时,vector::insert 会改变向量的大小。

【讨论】:

  • 感谢您的编辑,但我想发布与 OP 代码完全相同的内容。
  • 如果类没有默认构造函数,你如何实现这一点,因为那样调整大小不起作用
  • @Aly:几乎所有的类都有一个默认构造函数。对于少数不这样做的人,只需将要复制的对象以及计数传递给构造函数即可。 std::vector&lt;std::string&gt; v1(2, "HI");
  • @MooingDuck 我包含的类是我自己的,是否有默认构造函数的做法(尽管如果默认构造的类没有意义,则使用此类)?
  • @Aly:如果有一个默认构造函数没有意义,那就不要给它一个。没关系。不过,在使用调整大小功能时,您必须传递一个实例供 vector 复制。这很好。 v1.resize(4, "HI");
【解决方案2】:

首先你调整它的大小,让它有两个空字符串:

{"", ""}

然后在begin() + 1 或第二个元素之前插入"world"

{"", "world", ""}

然后在begin() 或第一个元素之前插入"world"

{"world", "", "world, ""}

然后您使用v1.at(1) 访问第二个元素并获取空字符串。

大概,您不希望std::vector::insert 在现有元素之间插入新元素。您想像使用数组一样使用operator[]

vector<string> v1(2);
v1[1] = "world";
v1[0] = "world";
cout << v1.at(1) << endl;

【讨论】:

    【解决方案3】:

    随机分配

    只需使用索引(显然,验证它是size)

    v1[index] = value;
    

    随机插入(验证该索引size)

    v1.insert(v1.begin() + index, value);
    

    按顺序在末尾插入/追加(不需要索引,您的值将插入到向量的末尾)

    v1.push_back(value);
    

    如果您打算插入许多值,请考虑在向量上调用reserve(),以便分配足够的内存来存储所有项目,否则当您插入数据时,随着向量的增长,您最终可能会进行多次重新分配

    【讨论】:

    • +1,可能想改写 push_back 以追加与插入。对我来说,至少在语义和概念上似乎更准确
    • 如果类没有默认构造函数,我不能调用 resize 对吗?在这种情况下,我如何拥有一定大小的向量并随机分配。还是我只需要创建一个空向量并继续插入?
    • 确切地说,如果你的向量包含“对象”而不是“指向对象的指针”,那么每次向量增长时都会复制对象(这非常低效),考虑存储大对象的指针并复制对象的构造函数。
    • @Aly:您可以将要复制的对象传递给构造函数,或者在没有默认构造函数的类的情况下传递给 resize 函数。工作得很好。
    • @emartel:他问的不是副本的效率,也不是指针。他在问如何在没有默认构造函数的类上调整大小。
    【解决方案4】:

    您的程序运行正常。您的错误在于代码的逻辑。

    插入不会更改存储在索引 1 处的字符串。它会将字符串放在位置 1,并将 1 之后的所有索引向右移动。

    开始第一个插入 第二个插入 ("","") -> ("", "world, "") -> ("world","","world","")

    因此,当您打印 v1.at(1) 时,您正在打印一个空字符串。

    要解决此问题,您需要使用:

    v1.at(1)="world"
    v1.at(0)="world"
    

    --或--

    v1[1] ="world"
    v1[0] ="world"
    

    这两个解决方案是等价的,但是第二个不会做任何边界检查。如果存在越界错误,第一个将引发错误。这无关紧要,只要您能保证您的索引永远不会越界。

    【讨论】:

      【解决方案5】:

      正如许多人所说,您可以使用operator[] 重新分配旧值,因为您已经调整了向量的大小或用其他值填充了它。 如果您的数组将始终具有固定大小,您可以使用std::array,它应该会提供性能提升,但会牺牲调整数组大小或在运行时确定其大小的能力。

      std::array<std::string,2> a1;
      a1[0] = "world";
      a1[1] = "world2";
      std::cout<<a1.at(1)<<std::endl; //outputs world2
      

      注意大小必须是静态的,所以不能这样:

      int numStrings;
      std::cin>>numStrings;
      std::array<std::string,numStrings> a2; //ERROR
      

      不幸的是,除了使用初始化列表之外,我认为没有任何方法可以在没有默认构造函数的情况下初始化 std::array

      struct T
      {
         T(std::string s):str(s){} //no default constructor
         std::string str;
      }
      std::array<T,2> a3 = {T(""), ""}; //you can use a conversion constructor implicitly
      

      显然,如果您想要一个包含大量对象的数组,这是不切实际的。

      【讨论】:

        猜你喜欢
        • 2020-07-09
        • 2015-06-10
        • 1970-01-01
        • 2017-12-26
        • 1970-01-01
        • 2013-03-22
        • 2016-07-10
        • 2016-07-26
        • 1970-01-01
        相关资源
        最近更新 更多