在C++中,何时需要使用指针而不是值?

10

我来自Java,现在正在学习C++。

据我所知,使用指针与Java中的引用变量非常相似,因为它们都传递一个内存地址来操作值。所以我觉得我已经对它们有了相当好的理解。我也知道这些变量存储在堆上。

然而,我发现在C++中还有另一种声明变量的方式,不需要使用new运算符/指针,只需像这样进行声明:

Employee boss("Frank");

这将创建一个Employee类型的变量,参数为“Frank”。这些变量存储在堆栈中。

因此,您有两种非常不同的创建变量的方式,它们都具有自己独特的行为(还涉及内存管理?)。

我的问题是,什么时候适合使用指针和值?最佳实践是什么?大多数情况下,我应该如何知道以何种方式声明变量?


1
“引用”是C++中的一个特定术语,因此我稍微编辑了您的问题,使用更正确的“值”。 - John Millikin
@John Millikin,感谢您澄清我的帖子,您正确理解了我的意图。我有时仍会在C ++术语上犯错。 - Mithrax
我建议在学习C++之前先放下Java。它们是不同的,如果你试图将它们进行类比,只会让自己和我都感到困惑。 - GManNickG
重复的,无论如何:https://dev59.com/pHNA5IYBdhLWcg3wKam3。 - GManNickG
@GMan,我对它们进行了比较,发现指针类似于Java的引用变量。然后我表明我理解了C++中两种变量创建方法背后的行为,我想要回答的唯一问题是何时适合使用特定的方法。 - Mithrax
显示剩余3条评论
7个回答

8

C++指针的操作与Java对象完全相同,它们可能无效(NULL)并且传递给程序非常便宜。

C++引用是指针的薄包装。它们不应该是无效的,但在某些情况下可能会是。例如,引用可能从一个NULL指针创建,或者它所引用的内存可能已被删除。

在你提供的代码示例中:

Employee boss("Frank");

你正在使用一种叫做“值”的东西。与指针和引用不同,值是它们所代表的对象本身,而不是一个间接引用。
我的问题是,何时使用指针VS [values]是合适的?最佳实践是什么?我应该如何知道大多数情况下应该以什么方式声明变量?
C++没有垃圾回收,因此在变量范围有限时使用值。例如,对于过程中的每个变量,可以将其分配在堆栈上,而不必担心内存,而不是使用new进行分配并使用delete进行释放。

6
这里涉及到两个不同的问题:创建对象和引用对象。

创建对象

对象可以在栈和堆中创建。如果使用你描述的语法:

Employee boss("Frank");

将在堆栈上创建它。如果您编写以下内容:

Employee* boss = new Employee("Frank");

它将在堆上创建它。如果您不熟悉堆栈和堆的概念,那么成为一名优秀的C++编程人员非常重要,所以请了解它!
引用对象有些不同。无论对象如何创建,都可以使用指针或引用(或只是标准变量)来引用它。在C/C++中使用引用和指针实际上是非常相似的,尽管存在重要的区别。
在使用指针或引用时,不会复制对象。
// No copies made:
Employee& frank = boss;  // Using References
Employee* frank = &boss; // Using a Pointer

当你两者都不使用时,会生成一个副本。
// Copy is made:
Employee frank = boss;

那么什么时候你会使用指针,何时会使用引用呢?我发现一个好的实践是只有在需要它为null时才使用指针。如果某些东西不应该是null,就把它做成引用。


2
注意:我将使用“对象”来指代对象和原始类型,如int、float等……这些在C++中不同(但通常可以忽略)。
当您创建一个仅在该作用域中受控且应在该作用域结束时终止的对象时,请使用值。此外,当您想要使用外部对象的副本,但只想处理副本而不是真实对象时,请使用值。例如:
int myFunction(int external_value1, Object external_value2){
    ---
}

当你创建一个对象并希望它不会在创建作用域结束时死亡(请确保将指针传递到其他作用域!),或者使用昂贵的副本(如容器)时,应使用指针/引用。或者当你想直接操作外部对象而不是其副本时,也需要使用指针/引用。这就是为什么函数的I/O参数通常是指针或引用的原因,因为你想直接操作一个外部对象(定义在函数作用域之外),而不是一个局部副本。例如:
int myOtherFunction(int *external_value1, Object *external_value2{
    ---
}

在这个例子中,如果你操作指向参数的值,你会影响到那个值:指针所指向的值,从而改变函数范围外的变量。 实际上是按值传递,但你只复制了指针,并使用它们来“攻击”外部值。
参考文献就像其他文章所述,只是指针的语法糖。一旦你理解了指针,你就理解了引用 ;)。

2
通常情况下,您应该尽可能使用引用。原因是 RAII。基本上,如果您使用RAII,则可以保证没有内存泄漏。
然而,在我看来,当您使用的对象非常昂贵时,应该使用指针。传递容器类型会导致容器的副本发生重复...这不是一个好主意。
最好的方法是使用智能指针...基本上是保持指针并跟踪指针引用数量的引用。这实际上是最佳方案...廉价的初始化/复制和引用计数几乎消除了内存泄漏。

1

不是真的;他在Java方面的背景导致了一些术语混淆。他不是在问指针与引用之间的区别,而是在问指针与堆栈分配的值之间的区别。 - John Millikin


0

两种不同的东西:如果你通过指针进行赋值,你最终会得到n对1的关系,你必须通过适当的资源管理来处理它们。在Java中通常会处理这个问题。

在所谓的“引用对象”中,你会得到不同的对象(需要跟踪等等)。


你怎么称呼“Reference Objects”,这样我才知道正确的术语?我不知道,所以我随便编了一个。 - Mithrax

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