C ++对象:我应该何时使用指针或引用

时间:2010-11-26 19:23:43

标签: c++ pointers reference

我可以使用一个对象作为它的指针或它的引用。我知道区别在于必须手动删除指针,并且引用仍然存在,直到它们超出范围。

我什么时候应该使用它们?有什么实际区别?

这些问题都没有解答我的怀疑:

9 个答案:

答案 0 :(得分:18)

引用基本上是一个带有限制的指针(必须在创建时绑定,不能反弹/为null)。如果您的代码使用这些限制是有意义的,那么使用引用而不是指针允许编译器警告您不小心违反它们。

这很像const限定符:语言可以在没有它的情况下存在,它只是作为一种额外的奖励功能,可以更容易地开发安全的代码。

答案 1 :(得分:8)

“指针我必须删除并引用它们,直到它们的范围完成。”

不,那是完全错误的。

必须删除[{1}}分配的对象[*]。不得删除未分配new的对象。可以指向未分配new的对象的指针,并且可以引用分配有new的对象。

指针或引用是一种访问对象的方式,但不是对象本身,并且与对象的创建方式无关。概念上的区别在于引用是对象的名称,而指针是包含另一个对象的地址的对象。实际差异,您如何选择使用哪一个,包括每个的语法,以及引用不能为空且无法重新安装的事实。

[*]与new。必须使用delete删除分配有new[]的数组。有一些工具可以帮助跟踪分配的资源并为你做这些调用,称为智能指针,因此,自己明确地进行调用应该是非常罕见的,而不是仅仅安排它来完成,但不过它必须完成。

答案 2 :(得分:3)

您有许多情况,其中参数不存在或无效,这可能取决于代码的运行时语义。在这种情况下,您可以使用指针并将其设置为NULL(0)以指示此状态。除此之外,

  • 可以将指针重新分配给新的 州。参考不能。这是 在某些情况下是可取的
  • 指针有助于转移所有者的语义。这特别有用 在多线程环境中,如果使用参数状态执行 一个单独的线程,你通常不会轮询直到线程退出。现在线程可以删除它。

答案 3 :(得分:3)

suszterpatt已经给出了很好的解释。如果你想要一个容易记住的经验法则,我建议如下:

如果可能,请使用引用,只有在无法避免的情况下才使用指针。

更短:更喜欢对指针的引用。

答案 4 :(得分:3)

这是另一个答案(也许我应该编辑第一个答案,但由于它有不同的焦点,我认为将它们分开是可以的。)

当你创建一个带有new的指针时,它的内存是保留的,它会一直存在,直到你在它上面调用delete - 但标识符的生命周期仍然限于代码块的结尾。如果在函数中创建对象并将它们附加到外部列表,则在函数返回后对象可以安全地保留在内存中,您仍然可以在没有标识符的情况下引用它们。

这是Umbra的一个(简化)示例,Umbra是我正在开发的C ++框架。存储在引擎中的模块列表(指向对象的指针)。引擎可以将对象附加到该列表:

void UmbraEngine::addModule (UmbraModule * module) {
    modules.push(module);
    module->id = modules.size() - 1;
}

检索一个:

UmbraModule * UmbraEngine::getModule (int id) {
    for (UmbraModule **it=modules.begin(); it != modules.end(); it++) {
        if ((*it)->id == id) return *it;
    }
}

现在,我可以在不知道标识符的情况下添加和获取模块:

int main() {
    UmbraEngine e;
    for (int i = 0; i < 10; i++) {
        e.addModule(new UmbraModule());
    }
    UmbraModule * m = e.getModule(5); //OK
    cout << m << endl; //"0x127f10" or whatever
    for (int j = 0; k < 10; j++) {
        UmbraModule mm; //not a pointer
        e.addModule(&mm);
    }
    m = e.getModule(15);
    cout << m << endl; //{null}
}

模块列表在程序的整个过程中都会持续存在,如果模块的实例化为new :),则无需关心模块的生命周期。所以基本上它 - 使用指针,你可以拥有永远不需要标识符(或名称,如果你愿意)的长寿命对象,以便引用它们。)。

另一个不错但非常简单的例子是:

void getVal (int * a) {
    *a = 10;
}
int main() {
    int b;
    getVal(&b);
    return b;
}

答案 5 :(得分:2)

呃......不完全是。它是具有范围的IDENTIFIER。当您使用new创建对象,但其标识符的范围结束时,您可能最终会出现内存泄漏(或者不是 - 取决于您想要实现的内容) - 对象在内存中,但您没有再次引用它的方法。

区别在于指针是内存中的地址,所以如果你有这样的代码:

int * a = new int;

a是一个指针。你可以打印它 - 你会得到类似“0x0023F1”的东西 - 它只是:一个地址。它没有值(尽管某些值存储在该地址的内存中)。

int b = 10;

b是一个值为10的变量。如果您打印它,您将获得10

现在,如果您希望a指向b的地址,您可以这样做:

a = &b; //a points to b's address

或者如果您希望a指向的地址具有b的值:

*a = b; //value of b is assigned to the address pointed by a

请编译此示例并注释/取消注释第13行和第14行以查看差异(注意标识符指向何处以及WHAT VALUE)。我希望输出结果不言自明。

#include <iostream>

using namespace std;

int main()
{
    int * a = new int;
    int b = 10;
    cout << "address of a: " << a << endl;
    cout << "address of b: " << &b << endl;
    cout << "value of a: " << *a << endl;
    cout << "value of b: " << b << endl;
    a = &b; //comment/uncomment
    //*a = b; //comment/uncomment
    cout << "address of a: " << a << endl;
    cout << "address of b: " << &b << endl;
    cout << "value of a: " << *a << endl;
    cout << "value of b: " << b << endl;
}

答案 6 :(得分:2)

让我们先回答最后一个问题。那么第一个问题会更有意义。

问:“指针和参考之间的实际区别是什么?”

答:引用只是另一个变量的本地假名。如果通过引用传递参数,则该参数与调用语句中列出的参数完全相同。但是,内部通常指针和引用之间没有区别。引用提供了“语法糖”,允许您减少当您真正想要访问给定变量的单个实例时必须执行的键入操作。

问:“我什么时候应该使用每个人?”

答:这将是个人偏好的问题。这是我遵循的基本规则。如果我将需要操作另一个范围中的变量,并且该变量是一个内部类型,一个应该像内在类型一样使用的类(即std :: string等等),或者一个const类实例,然后我通过引用传递。否则,我会通过指针传递。

答案 7 :(得分:0)

问题是你不能重新引用另一个对象的引用。引用绑定编译时间,不能为null或反弹。因此,如果你的疑问是那么指针并不多余:)

答案 8 :(得分:0)

正如我的c ++老师曾经说过的那样,指针指向内存位置,而引用是别名。因此,主要的优点是它们的使用方式与它们引用的对象名称相同,但是在通过传递它的对象不可用的范围内。

虽然指针可以重定向到其他位置,但是引用就像常量指针一样,无法重定向。因此,引用不能用于遍历函数等中的数组。

但是,指针是一个单独的实体会占用一些内存,但引用与引用的对象相同不会占用任何额外的空间。这是它的优点之一。

我还读过参考的处理时间较少,

as

int&amp; i = b;

i ++;花费的时间比

int * j = b;

(* j)++;

但我还没有证实这一点。如果有人能说清楚这个说法那就太棒了。

欢迎评论:)