2011-03-26 70 views
4

我碰到一些代码,用这样的方法来:常数引用到指针

QList<Item*> itemList; 
void addItem(Item* const& item) 
{ 
    itemList.append(item); 
} 

现在,我看不出这之间的任何有意义的区别:

QList<Item*> itemList; 
void addItem(Item* item) 
{ 
    itemList.append(item); 
} 

但很明显有人走出他们的方式来使用这种奇怪的类型。或者一个重构工具可能出错了。

是否有任何理由保持该函数签名?某种角色案件的行为有所不同?我想不出任何事情。

+5

可能只是'QList :: append'签名的复制粘贴,它需要'const T&',因为它是通用的,而且它知道,'T'是复制代价昂贵的。编辑:嘿,不是字面上的复制粘贴,因为你的代码有'T const',而我刚刚检查过的QT文档有'const T&'。但是精神上一个副本,因为意思是一样的。 – 2011-03-26 00:11:22

+0

@Steve这不是通过引用传递一个对象,而是将一个指针传递给一个对象。将不会有昂贵的复制。 我不能想到任何东西,但可能使用常量迭代器? – 2011-03-26 00:15:36

+0

@Khaled:我知道。我并不是说'Item *'拷贝的代价可能很高。我在说,在'QList'中,'T'可能要复制很昂贵。这个程序员有(我怀疑)复制了一些与'Item *'的具体情况无关的代码。由于通过'const'引用传递指针并没有什么错,他们甚至可能会故意保留它,以便它看起来与'QList :: append'一致 - 当然还有不熟悉'QList'的人,这是不协调的因为你通常不会以这种方式传递指针。 – 2011-03-26 00:17:41

回答

4

唯一的区别是,在第一个版本中,您不允许更改函数内部的本地item的值(您仍然可以修改它指向的Item)。因此,如果您想要Item*由于某种原因保存不同的值,您将被迫使用Item*类型的另一个本地,并且该函数将占用堆栈空间(boo hoo)的额外字节数(sizeof(intptr_t))。

不是惊天动地,我知道。

+0

谢谢。这似乎是两者之间差异的一个很好的总结。 – cgmb 2011-03-26 00:25:38

+0

“该函数将消耗额外的sizeof(intptr_t)字节的堆栈空间” - 如果编译器足够垃圾(或者控制流程足够不可预知),则不会意识到“item”可以在停止使用它的地方被删除,并开始使用你的额外变量。 – 2011-03-26 00:27:56

+0

为什么没有提到这样一个事实,即第一项是这个答案中的参考,只是它是一个常量?这不也是一个区别 – Julius 2014-07-22 11:27:27

1

它是对const指针的引用,这意味着你得到这个指针的昵称,但是你不能改变它指向的地址。

一个指针副本是等价的,如果你使它成为const。

我闻到了代码到这一点的历史变化序列,当然在几次命名重构之后。

0

它是一个可变引用,指向一个可变值的常量指针。

引用将允许您修改引用的引用,但引用的类型是常量指针,所以指针的值不能更改。指针指向的值可以更改。

void* const &

  • 原始指针:不可变
  • 引用的指针:不可变
  • 原始值:易变

传递一个恒定指针直接将是等效的。

void* const

  • 原始指针:不可变
  • 复制的指针:不可变
  • 原始值:易变
+0

有没有这样的事情作为一个可变的参考。引用默认为const,这就是为什么你不能声明它们为const(因为它是多余的) – 2011-03-26 04:24:07

+0

不正确。一个可变引用是一个引用,通过该引用,该值可以被突变。你指的是'重新引用',这在C++中是不可能的。试图使参考本身不变是多余的。 – 2011-03-29 16:56:41

+0

对不起,但你写了“可变引用常量指针”。这只是没有任何意义。在你的评论定义后,你必须说“const指向一个指针”。或者你可以正确地说“引用const指针”。但“可变引用常量指针”只是纯粹的废话。 – 2011-03-29 23:44:07

1

第一声明意味着 “项是一个常数指针参考变量”。您不能将项目更改为指向ITEM类型的另一个数据,并且它是一个引用,因此它指向作为被调用函数中参数传递的指针。

伪代码:Item * myItem = new Pen(); additem(myItem); 第一次声明确保additem函数不会改变笔对象,因为它是一个常量引用,它也不会复制myItem的内容,它只是指向myItem的内存位置。 第二个声明具有复制myItem内容的开销。

0

发生在我身上的另一个重大差异是在堆栈上传递的实际数据。在Item*版本中,Item*作为参数传递,需要一个取消引用才能获得Item值。但是,由于引用是通过传递指针在最终机器代码中实现的,所以Item* const&版本实际上传递Item**作为参数,需要两个取消引用以得到Item值。

这也解释了为什么你需要额外的栈空间得到修改Item*版本 - 您的来电者实际上并没有给你在堆栈上Item*(或寄存器),您可以更动的,只有你有一个Item**(或在C++ land中为Item* const&)。