![](/img/trans.png)
[英]OpenACC - Complex loop carried dependence of a->,c->,b-> prevents parallelization
[英]Pointers to pointers: Difference between *a = b->c and a = &b->c
回顾两星编程文章,我不禁看到以下两行之间差异的重要性:
*curr = entry->next;
curr = &entry->next;
我可以看到的唯一区别是第一行更改*curr
指向下一个节点,第二行使一个全新的**
指向该节点成员(这是下一循环中的上一个节点)
在我看来,在第一个if块中free
条目会阻止第二行在下一个循环中正常工作,但是在那种情况下为什么不在两种情况下都只使用第一行呢? 这是性能问题吗?
编辑:请阅读上方链接中名为“两星编程”的第二个代码块
编辑:所以我似乎解释得不好(抱歉!),所以让我看看是否可以解释得更详细些。
这是本文中的源代码。
void remove_if(node ** head, remove_fn rm)
{
for (node** curr = head; *curr; )
{
node * entry = *curr;
if (rm(entry))
{
*curr = entry->next;
free(entry);
}
else
curr = &entry->next;
}
}
据我估算, curr = &entry->next;
行不是必需的,您可以使用其他两次:
void remove_if(node ** head, remove_fn rm)
{
for (node** curr = head; *curr; )
{
node * entry = *curr;
if (rm(entry))
{
*curr = entry->next;
free(entry);
}
else
*curr = entry->next;
}
}
然后,您可以将其移至if语句上方,并节省几行:
void remove_if(node ** head, remove_fn rm)
{
for (node** curr = head; *curr; )
{
node * entry = *curr;
*curr = entry->next;
if (rm(entry))
{
free(entry);
}
}
}
实际上,看起来您根本不需要指针,可以做到这一点:
void remove_if(node * head, remove_fn rm)
{
for (node* curr = head; curr; )
{
node * entry = curr;
curr = entry->next;
if (rm(entry))
{
free(entry);
}
}
}
那么为什么他们要这么做呢? 性能? 还有其他晦涩的地方吗?
两者是完全不同的。
curr = &entry->next;
接受变量entry->next
的地址,并将其分配给指针变量curr
。 完成此任务后,以前指向的任何curr都不会更改,但将少引用它。
*curr = entry->next;
完全不更改curr
的值,但是更改其指向的值,该引用的引用数与以前相同,但引用的值不同。
是的,这两个结果都将使*curr
等于entry->next
,但实际上它们将不同的值写入不同的内存位置,并具有其他重要的副作用。
本文中的代码是正确的,并且所有三个建议的变体都不正确。 让我们先看一下正确的代码,并加上一些注释:
void remove_if(node ** head, remove_fn rm)
{
// node ** passed to allow use to modify caller's head pointer
for (node** curr = head; *curr; )
{
// curr is a local variable, that points to a node pointer
// curr points either to the caller's head pointer, or to
// a next pointer within the list
node * entry = *curr;
if (rm(entry))
{
// remove this entry, which means modifying the list
*curr = entry->next;
// modify *curr modifies either caller's head pointer
// or a next pointer
free(entry);
}
else
// did not remove, so do not modify the list
curr = &entry->next;
}
}
这里要注意的关键点:
*curr = entry->next
修改列表。 curr = &entry->next
不会修改列表。 您提出的前两个版本是错误的,因为它们确实
*curr = entry->next
在每次迭代中。 分配给*curr
会修改列表。 想象一个场景,其中rm()
总是返回false。 在这种情况下,您绝不能修改列表,但是每次循环时都要对其进行修改。
最终的变体是错误的,因为您只传递一个node *
则无法修改调用方的头指针。 实际上,最终变体根本不会修改列表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.