关于指针:在C ++中声明向量和集合

Declaring vectors and sets in C++

这是我第一次使用C++中的STL容器,在谷歌中看到不同的例子时,我注意到了一些向量和集合的声明。

如果您有一个类A,并且希望将这些元素存储在一个向量中,那么您可以使用指向对象的指针(如下所示)。而对于集合,则使用声明中的实际对象。我想知道这样做是否有特别的原因,或者只是在我看到的例子中发生的。

1
2
vector<*A> cont1;
set<A> cont2;

在大多数情况下,您最终将使用具有自动存储持续时间的对象容器,而不是指针/智能指针,因为这样的容器将为您处理难看的内存管理。

在大多数情况下,简单的std::vector就足够了。这些情况非常罕见,需要使用std::vector来代替。这种情况的一个例子可能是在使用这个容器的元素时需要实现运行时多态性。另一个例子可能是由于复制A时可能出现性能问题而使用指针。另一个原因是避免对象切片。

好的实践是始终使用对象容器,除非您有充分的理由使用指针容器。即使需要保留指针,也要使用智能指针。

相关问题:如何在C++中使用指针来动态分配对象时避免内存泄漏?C++:对象向量与指向新对象指针的向量?


我不知道这是惯例。

但是,这样做的一个可能原因是,随着vector的大小调整,所包含的对象可以在内存中移动。如果包含的对象将其this指针提供给其他对象,则该指针在resize之后可能无效。通过存储指针和自己管理内存,对象不会因此而受损。

使用set时,您不会观察到相同的行为,因为集合往往被实现为树。请注意:我不认为C++标准库对此有任何保证。

如果作者试图利用set来利用这一点,那么他们就滥用了封装规则。如果没有,那么您提供的两个示例可能是无关的。还有许多其他的原因可以让您将指针(或不)存储在容器中,并且您可以自由选择。


向量是简单的容器,可以容纳任何可复制的内容。因此,根据您的需要,您可以将对象或指向其中对象的指针放在其中。

虽然集合也可以包含指针,但这样做通常没有多大意义。集合是有序的容器,这意味着创建集合时,需要指定比较函数。如果不指定一个比较函数,则使用默认比较函数(std::less<>),这取决于要在集合中存储的内容,以便定义operator<。这实际上似乎适用于指针,因为您可以将指针与<进行比较,但它比较的是指针,而不是指针指向的对象,因此集合最终将按对象在内存中的相对位置排序。


集合和向量之间的真正区别在于集合包含所有唯一元素,并且其操作的运行时间不同。它们根本就不等同!

不同的原因是可以有两个动态分配的对象,它们相等,但存储在不同的位置。如果你这样做:

1
2
3
4
A a,b;
std::vector<A> myVector;
myVector.push_back(a);
myVector.push_back(b);

那么myvector将包含两个元素,但在以下情况下:

1
2
3
4
A a,b;
std::set<A> mySet;
mySet.insert(a);
mySet.insert(b);

myset将只包含一个。如果我们使用指针,情况就不会是这样了。

此外,动态分配用于向量的项的原因(如其他人所指出的)是为了减少插入的开销。

干杯!


这取决于你想储存什么。

1
std::vector<A*> myVector;

…将创建存储指向A类型的指针的向量。

1
std::set<A> mySet;

…将创建一个存储类型的实际实例的集合。

您可以很容易地将实际实例存储在一个向量中:

1
std::vector<A> myVector;

或集合中的指针:

1
std::set<A*> mySet;

1
2
3
4
vector<A*> cont1;
cont1.push_back( new A( whatever ) );
vector<A> cont2;
cont2.push_back( A( whatever ) );

这取决于你有什么用例。是否要存储对象或指针?

请注意,第一个示例需要您手动对每个对象执行delete,而第二个示例将为您处理删除操作。尽可能使用第二个,除非你知道你在做什么。它还可以确保任务的安全。


这只是你遇到的例子。可以在向量中存储从对象本身到指针到函数指针的任何内容。还可以将其他向量存储在向量中以定义多维向量:

1
2
3
4
5
// define 4x4 vector
vector< vector<int> > vec(4, vector<int>(4));

vec[i][j] = a;     // write
int b = vec[i][j]; // read