0

从函数返回指向非的指针的最佳实践是什么const,该指针是通过修改(非const)指向的指针获得的const?像这样:

NODE *top_level(const NODE *input)
{
  while (input->parent != nullptr)
    input = input->parent;  // NODE::parent is (non-const) NODE*

  return input;  // Compile failure: 
                 // Cannot convert from 'const NODE *' to 'NODE *'
}

我可以const_castconst返回时离开,这似乎很好,但有更好的方法吗?

4

3 回答 3

6

至少在标准库中,最佳实践是提供const和非const重载。例如std::strchr被声明<cstring>

char *strchr(char *s, int c);
char const *strchr(char const *s, int c);

同样,类似的函数也std::map<T>::find有重载,例如

iterator find(const Key& key);
const_iterator find(const Key& key) const;

请注意,const第一个版本没有限定符,即使它find本身没有理由修改map.(*) 关键是你从中得到的东西find可以用来修改地图,所以通过一种“传递性可变性”,find不能const。我认为,同样的情况也适用于你的问题。

或者,您可以使用 a const_cast,但对我来说,这感觉就像违背了承诺。

这种情况的有趣之处在于,如果您可以保证永远不会在树的顶部项目(或任何输入)上调用您的函数,那么就不需要强制转换或重载:

struct node {
    node *parent;
};

node *top(node const *n)
{
    node *p = n->parent;
    while (p->parent != 0)
        p = p->parent;
    return p;
}

编译没有任何警告。

(*) 如果std::map实现为展开树,find则必须对其进行修改,但我认为由于复杂性保证,标准不允许展开树。

于 2013-02-06T11:55:56.310 回答
2

[编辑:在我们的两次编辑之后,我认为我的答案和 larsmans' 现在是相同的,但是对于不同的选项,事情的顺序不同,细节层次也不同。我鼓励人们不要费心赞成这个答案,除非你看到它和 larsmans' 之间的一些重要区别。如果没人找到,我会删除它。]

如果您确定const-ness 不应该*input暗示该函数不会为您提供修改列表更靠前的某个其他节点的方法,那么解决方法是:

NODE *top_level(const NODE *input_)
{
  NODE *input = const_cast<NODE*>(input_);
  while (input->parent != nullptr)
    input = input->parent;

  return input;
}

但这对我来说似乎是错误的,因为该函数可以返回与传入的完全相同的指针值

因此,由于它可以为其他代码(尽管是调用者)提供修改其输入的方法,因此不应将其输入标记为const. “正确”的解决方案是提供 const 和非 const 重载,因为这就是避免编写“走私 constness”的函数的方式,例如非重载 C 版本的strstr和其他返回非 const 的字符串搜索函数。

如果不是因为从指向同一个节点的指针中删除 const 的风险(想象一下输入以某种方式保证不是顶级节点,并想象你仍然确定第一个节点的 constness 应该'不暗示列表中其他节点的常量),那么你可以这样写:

NODE *top_level(const NODE *input)
{
  NODE *result = input->parent;
  while (result->parent != nullptr)
    result = result->parent;

  return result;
}

请注意,我们不再需要const_cast,当我们添加使函数本身成为负责任的 const 安全公民所必需的假设时,它就消失了。系统有效!;-)

于 2013-02-06T12:24:16.277 回答
0

至少在接口级别,通常的解决方案是重载const,提供两个函数NODE const* top_level( NODE const* input )NODE* top_level( NODE* input )。如果您不想复制代码,则可以使用const_cast另一个来实现一个。

于 2013-02-06T11:55:33.387 回答