如何在C++中随机分配向量?

13

我是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;

2
数组(仅是指针)这句话的意思是什么?数组绝对不仅仅是指针。 - Lightness Races in Orbit
@LightnessRacesinOrbit 我的意思是,不要使用vectorcv::Mat,而是使用cv::Mat*。 - Aly
那么你的意思是一个指向动态分配的内存块的指针,该内存块足够大,可以容纳N个连续的cv :: Mat对象。 - Lightness Races in Orbit
5个回答

19

不要放弃,比那更容易。

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

cout << v1[1] << endl;

vector::insert 用于向 vector 中添加项,而不是替换已经存在的项。换言之,vector::insert 会改变 vector 的大小。


谢谢您的编辑,但我想发布与原帖代码完全相同的代码。 - john
如果类没有默认构造函数,那么如何实现这一点,因为 resize 将无法工作。 - Aly
@Aly:几乎所有的类都有默认构造函数。对于那些没有默认构造函数的类,只需将一个要复制的对象和计数传递给构造函数即可。std::vector<std::string> v1(2, "HI"); - Mooing Duck
@MooingDuck 我所包含的类是我自己的,是否有默认构造函数是一种惯例(尽管如果使用该类进行默认构造可能没有意义)? - Aly
@Aly:如果没有默认构造函数是没有意义的,那就不要提供它。这很好。但是,在使用调整大小函数时,您将不得不传递一个实例给vector进行复制。这也很好。v1.resize(4, "HI"); - Mooing Duck
@Aly。如果没有意义,那就不要添加一个只是为了使容器工作更容易的东西。你走在正确的轨道上:使用.insert两次或按照上面建议的提供默认值来.resize...然后像答案中所示使用op[]编辑元素。 - Lightness Races in Orbit

12

首先,您需要将其调整大小以获得两个空字符串:

{"", ""}

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

{"", "world", ""}

然后在begin()或第1个元素之前插入"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;

10

随机分配

只需使用索引(显然要验证它是否 < size

v1[index] = value;

随机插入(验证索引<size

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

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

v1.push_back(value);

如果您计划插入许多值,请考虑在向矢量中调用reserve(),以便足够的内存可以分配以存储所有项目,否则当您插入数据时,随着矢量增长,可能会出现许多重新分配。


2
+1,可能需要重新措辞push_back为append而不是insert。对我来说,这似乎更语义化和概念上准确。 - im so confused
@Aly:你可以将一个对象传递给构造函数进行复制,或者对于没有默认构造函数的类,可以将其传递给resize函数。这样做完全没问题。 - Mooing Duck
@emartel:他并没有询问复制或指针的效率。他是在问如果一个类没有默认构造函数,resize函数如何工作。 - Mooing Duck
@Aly 不,你需要 a) 分配对象,b) 将其插入/推到你的向量中,c) 当你销毁向量(即在它的所有者析构函数中)时,你需要手动遍历每个向量元素并调用 delete。 - emartel
除非它们非常简单(纯数据(int,float等)或由几个纯数据成员组成的简单对象 - 即:具有x,y和z分量的3D向量),否则我不会使用对象的向量。 - emartel
显示剩余4条评论

6
你的程序运行正确。你的错误在代码逻辑上。
插入操作不会改变存储在索引1处的字符串。它是将一个字符串放在位置1,并将1之后的所有索引向右移动。
开始状态 -> 第一次插入 -> 第二次插入 ("","") -> ("", "world, "") -> ("world","","world","")
所以,当你打印v1.at(1)时,你打印的是一个空字符串。
要解决这个问题,你需要使用:
v1.at(1)="world"
v1.at(0)="world"

--or--

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

这两种解决方案是等价的,但是第二种方案不会进行任何边界检查。如果出现越界错误,第一种方案将抛出错误。只要能保证不会索引越界,这就没关系了。


2

就像许多人所说的那样,如果你已经确定了向量的大小或填充了其他值,你可以使用 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

显然,如果你想要一个包含大量对象的数组,这并不实用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接