何时在C++中使用指针

6

我刚开始学习C++中的指针,不太确定何时使用指针,何时使用实际对象。

例如,在我的一个作业中,我们必须构建一个gPolyline类,其中每个点由gVector定义。目前,我的gPolyline类变量如下:

private:
vector<gVector3*> points;

如果我使用 vector< gVector3 > points ,会有什么不同?此外,何时使用指针有一般的经验法则吗?谢谢!

内存复制是最大的影响。如果你只谈论三个整数,那么可以忽略不计。 - pestilence669
2
@mloskot - 如果你仔细查看,就会发现Alice只问了四个问题,并且接受了其他三个问题的答案。因此,她显然知道SO是如何工作的,而且可能正在评估答案以找出哪个答案最好地回答了她的问题。 - ChrisF
1
@Neil和@ChrisF - 我并没有说有任何要求。你们关于等待时间超过1-2小时的观点是正确的。向Alice问好。 - mloskot
5个回答

2
一般的经验法则是需要时使用指针,可以时使用值或引用。
如果您使用vector<gVector3>插入元素,将会复制这些元素,并且这些元素将不再连接到您插入的项。当您存储指针时,向量只是引用您插入的对象。
因此,如果您希望多个向量共享相同的元素,以便元素中的更改在所有向量中反映出来,则需要向量包含指针。如果您不需要这样的功能,则通常最好存储值,例如它可以使您免于担心何时删除所有这些指向对象的指针。

1
通常情况下,当必须使用指针时,最好使用引用或者对象(考虑值)。
首先,您需要知道 gVector3 是否符合标准容器的要求,即类型 gVector3 是否可复制和可分配。如果 gVector3 也可以默认构造(请参见下面的更新说明),那么这将非常有用。
假设它确实符合要求,那么您有两个选择,直接在 std::vector 中存储 gVector3 对象。
std::vector<gVector3> points;
points.push_back(gVector(1, 2, 3)); // std::vector will make a copy of passed object

或手动管理gVector3对象的创建(和销毁)。

std::vector points; points.push_back(new gVector3(1, 2, 3)); //...

当不再需要points数组时,请记得遍历所有元素并调用delete运算符。

现在,您可以选择将gVector3视为对象进行操作(可以将其视为值或值对象),因为(如果,见上面的条件)由于复制构造函数和赋值运算符的可用性,以下操作是可能的:

gVector3 v1(1, 2, 3);
gVector3 v2;
v2 = v1; // assignment
gVector3 v3(v2); // copy construction

或者您可能希望或需要使用 new 操作符在动态存储中分配 gVector3 对象。也就是说,您可能希望或需要自行管理这些对象的生命周期。

顺便说一下,您可能也想知道 何时应该使用引用,何时应该使用指针?

更新:以下是对 默认可构建性 注意事项的解释。感谢 Neil 指出最初存在不清楚之处。正如 Neil 正确地注意到的那样,这并非 C++ 标准所要求的,但我指出这个特性是重要且有用的。如果类型 T 不具备默认可构建性(这并非 C++ 标准所要求),则用户应该意识到潜在的问题,我将在下面进行说明:

#include <vector>
struct T
{
    int i;
    T(int i) : i(i) {}
};
int main()
{
    // Request vector of 10 elements
    std::vector<T> v(10); // Compilation error about missing T::T() function/ctor
}

1
你对可复制和可赋值的要求是正确的 - 但你对默认构造函数的要求是错误的 - 没有这样的要求。 - anon
非常好的观点,加1分。我已经更新了我的答案,使其更加清晰。谢谢! - mloskot
你可以这样说:std::vector<T> v(10, T(0)); 我也犯过这个错误 - 你可以在我的博客文章中看到有关默认构造函数的内容,网址为http://punchlet.wordpress.com/2009/12/03/letter-the-third。 - anon
是的,这是正确的,但与类型T的特定示例(或您博客中类似的类型)紧密相关。然而,有时类型更复杂,模拟虚拟或默认构造可能并不容易甚至不可能。 - mloskot

1

在现代C++中,指针通常应该避免使用。如今指针的主要目的是因为指针可以是多态的,而显式对象则不行。

然而,当您需要多态性时,最好使用智能指针类,例如std::shared_ptr(如果您的编译器支持C++0x扩展),std::tr1::shared_ptr(如果您的编译器不支持C++0x但支持TR1)或boost::shared_ptr


我不知道你所说的“现代C ++”是什么意思,但在我参与的许多大型项目中,我不得不将代码从STL_Struct<object>迁移到STL_Struct<object *> :)有时候,出于我在上面回答中澄清的原因,您确实需要指向对象而不是对象本身的指针...但我会承认通常没有必要使用指针。 - Mahmoud Al-Qudsi
通过“现代C ++”,我指的是C ++ 03标准,或ANSI / ISO标准化的C ++。一些较旧的编译器没有完全实现标准,并且需要使用指针来弥补这些编译器的不一致性。 - Billy ONeal

0
你可以使用指针或对象 - 在一天结束时,它们实际上是相同的。
如果你有一个指针,你需要为实际对象分配空间(然后指向它)。无论你存储指针还是对象本身,如果你有一百万个对象,在一天结束时,你将在内存中分配一百万个对象的空间。
什么时候应该使用指针呢?如果你需要传递对象本身,修改数据结构中的单个元素而不必每次都检索它们,或者如果你正在使用自定义内存管理器来管理对象的分配、释放和清除。
将对象本身放入STL结构中更容易、更简单。它需要 less * and -> 操作符,你可能会发现这些操作符很难理解。某些STL对象需要在其默认格式中具有对象本身而不是指针(即需要对条目进行哈希的哈希表 - 你想要哈希对象,而不是指向它的指针),但你可以通过覆盖函数等方式绕过这些问题。
底线:在合适时使用指针,在其他情况下使用对象。

在这里使用指针仍然不是一个好主意。更好的方法是使用STL的迭代器并以这种方式迭代集合。如果您担心对象空间,最好使用某种形式的shared_ptr。最后,使用原始指针会破坏所有具有删除语义的标准算法,例如std::removestd::remove_ifstd::uniquestd::replacestd::replace_if等。 - Billy ONeal

0

通常你使用对象。
吃一个苹果比吃一个插在棍子上的苹果容易(好吧,两米长的棍子因为我喜欢糖苹果)。

在这种情况下,只需将其设置为vector<gVector3>

如果你有一个vector<g3Vector*>,这意味着你正在动态分配新的g3Vector对象(使用new运算符)。如果是这样,那么你需要在某个时候调用delete来删除这些指针,而std::Vector并不设计做到这一点。

但每个规则都有例外。

如果g3Vector是一个成本很高的巨大对象(很难判断,请阅读你的文档),那么将其存储为指针可能更有效。但在这种情况下,我会使用boost::ptr_vector<g3Vector>,因为它可以自动管理对象的生命周期。


对不起,这条评论是针对另一篇帖子的。 - Billy ONeal

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