是否可以从数组中初始化字符串向量?如果是这样,如何?

Is it possible to initialize a vector of strings from an array? If so, how?

例如,在 GeeksForGeeks.org 上,贡献用户“Kartik”提供了以下用于初始化整数向量的示例:

// CPP program to initialize a vector from 
// an array. 
#include <bits/stdc++.h> 
using namespace std; 

int main() 
{ 
    int arr[] = { 10, 20, 30 }; 
    int n = sizeof(arr) / sizeof(arr[0]); 

    vector<int> vect(arr, arr + n); 

    for (int x : vect) 
        cout << x << " "; 

    return 0; 
} 

如果我理解正确,sizeof(arr) 是一些数字(我假设它是数组的长度 arr;即 3,如果我错了请纠正我) 除以 sizeof(arr[0])(我假设为 1)——基本上只是一种迂回的说法 3/1 = 3.

此时,vector<int> vect(arr, arr + n) 似乎是一个大小为 3 的向量,所有值都初始化为 arr + n(我假设这是一种表达“使用来自arr实例化,再说一遍,如有不妥请指正)。

通过任何魔法,输出是10 20 30

现在,不管我上面的任何漫无边际的内容是否连贯甚至是正确的,我的主要问题是:是否可以使用相同的技术来实例化一些示例 vector<string> stringVector 以便它可以迭代通过某些示例 string stringArray[] = { "wordA", "wordB", "wordC" } 指定的字符串?因为,据我所知,字符串没有数值,所以我想如果不遇到一些时髦的垃圾就很难说 vector<string> stringVector(stringArray, stringArray + n) 。那么,如果可能的话,人们会怎么做呢?

作为骑手,为什么,或者在什么类型的实例中,会有人想为向量做这个吗?从数组(据我了解它具有恒定大小)实例化它是否会破坏向量的目的?

就像免责声明一样,我是 C++ 的新手,很多面向对象的语法都涉及 std::vector<_Ty, _Alloc>::vector...等。对我来说完全没有意义,所以我可能需要在答案中对此进行解释。

对于所有阅读本文的人,感谢您抽出宝贵时间。我希望你今天过得愉快!

是的,您可以这样做 - 您只需要定义 String 的构造函数将采用的内容(即 'const char')

   const char * arr[] = { "abc","def","ghi" };
    int n = sizeof(arr) / sizeof(arr[0]);

    vector<string> vect(arr, arr + n);

    for (string &x : vect)
        cout << x << " ";

这实际上是从两个迭代器创建向量(指针大致上是一个迭代器):

https://en.cppreference.com/w/cpp/container/vector/vector

Constructs the container with the contents of the range [first, last).
This constructor has the same effect as vector(static_cast<size_type>(first), static_cast<value_type>(last), a) if InputIt is an integral type.

正如@MartinYork 指出的那样,使用 C++ 语法更具可读性:

    const char * arr[] = { "abc","def","ghi" };
    vector<string> vect(std::begin(arr), std::end(arr)); 

这是您的操作方式。请注意,获取数组的长度有点尴尬,但这只是因为数组不携带该信息(使用向量!)。

#include<string>
#include<vector>
#include<iterator>
#include<iostream>


int main()
{
    std::string arr[] = {"abc", "def", "ghi"};
    std::vector<std::string> tmp;
    std::copy(arr, arr + sizeof(arr)/sizeof(arr[0]), std::back_inserter(tmp));
    for(auto str : tmp) {
        std::cout<<str<<"\n";
    }
}

更新:是的,关于对数组使用 std::beginstd::end 的好处。

那么如果可以的话,你会怎么做呢?


只需使用 vector 5 号构造函数,它接受范围开始和结束的迭代器

  1. Constructs the container with the contents of the range [first, last).
#include <iostream>
#include <vector>
#include <string>

int main()
{
    std::string arr[] = { "wordA", "wordB", "wordC" };    
    std::vector<std::string> v {std::begin(arr), std::end(arr)};

    for (auto& str : v)
        std::cout << str << "\n";
    return 0;
}

澄清:

  • sizeof(arr):returns 数组的大小,以字节为单位,它是 12,因为它有 3 个 int,并且每个 int 在大多数实现中都有一个大小为 4 个字节,因此 3 个字节 x 4 = 12 个字节。
  • sizeof(arr[0]): returns 数组第一个元素的大小(以字节为单位),它是 4,因为它是一个 int 数组。
  • vector<int> vect(arr, arr + n): 向量 class 有 multiple constructors。这里我们没有使用您正在考虑的构造函数。我们正在使用一个构造函数,该构造函数采用一系列元素的开始和结束迭代器,并制作这些元素的副本。指针可以用作迭代器,在这种情况下,arr 是开始迭代器,arr + n 是结束迭代器。

注:int* + int returns int*.

注意:我们还应该考虑到数组的“结尾”是指向数组中最后一项之后的下一个space的指针,构造函数将复制除过去的项目之外的所有项目结束。

答案:

是的,请记住,这里构造函数采用的是迭代器,而不是数组的任何项,因此我们可以像这样轻松完成,只需稍加改动:

#include <bits/stdc++.h>
using namespace std;

int main()
{
    // changed int to string and the array values
    string arr[] = { "one", "two", "three" };
    int n = sizeof(arr) / sizeof(arr[0]);

    // changed int to string
    vector<string> vect(arr, arr + n);
    
    // changed int to string
    for (string x : vect)
        cout << x << " ";
    return 0;
}

sizeof(arr)

sizeof gets the size of an object in bytes. The size of an object is the total number of bytes required by the object. Note that I'm using "object" in the C++ context,不是 OOP 上下文(class 的实例)。

给定类型的对象的大小始终相同。包含 "a"std::string 与包含 War 和 Peace 的完整文本的 string 大小相同。任何看起来具有可变大小的对象实际上都包含对存储在别处的可变长度数据的引用。在最基本的 std::string 的情况下,它是一个指向动态分配数组的指针和一个整数,用于跟踪 string 实际使用了多少动态分配的数组。 std::vector 类似,通常它是一个指向其数据开始的指针,一个指向其数据末尾的指针,以及一个指向数据中第一个空位置的指针。无论 vector 有多大,sizeof(vector) 都会 return 指针的大小、vector 实现中的任何其他簿记变量,以及保证需要的任何填充正确 memory alignment.

这意味着数组中的每一项始终具有相同的大小,因此彼此之间的距离也相同。

通过任何魔法...

上面的意思是数组的总大小除以数组中一个元素的大小,sizeof(arr) / sizeof(arr[0])将始终提供数组中元素的数量。数组包含什么,数字的还是其他的并不重要。当然还有更漂亮的方式,比如

template <class T, size_t N>
size_t getsize (const T (&array)[N])
{
    return N;
}

以后

size_t n = getsize(arr);

作为骑手,为什么,或者在什么类型的实例中,会有人想要对矢量执行此操作?

在过去,不能直接构造一个 vector 预加载数据。没有人愿意编写任意行数的 push_back 来手动输入所有值,这太无聊了,程序员几乎总是有更好的事情要做,而且注入错误的几率太高了。但是,如果您根本需要 vector,您可以很好且轻松地格式化一个数组并将该数组提供给 vector。很多时候你可以靠数组本身生活,因为内容是不变的,或者最坏的情况下只会被洗牌。

但如果内容的数量可能会发生变化,可能是 vector 的时候了。如果您要添加项目并且不知道上限,那么现在是 vector 的时候了。如果您要拨入需要 vector 的 API,则需要 vector.

我不能代表所有人,但我假设很多人和我一样喜欢为 vector 进行简单易行的数组式初始化,lists, maps, 以及其他普通帮派。

我们被迫编写生成适当代码的程序来填充 vector 或定义一个数组并将数组复制到 vector 中,就像上面的例子一样。

在 C++11 中,我们用 std::initialzer_list and a variety of new initialization options1 实现了我们的愿望,允许

vector<string> vect{"abc","def","ghi"};

消除了您发现自己将数组复制到库容器中的大多数情况。群众欢欣鼓舞。

这与许多工具如 std::size, std::begin and std::end to make converting an array into a vector a cakewalk. Assuming you don't pass the array into a function 首先一致。

1 不幸的是初始化选项列表可以得到 a lil' bewildering