const输入与非const输出

use*_*601 15 c++

我有一个遍历对象树的函数,不会修改树中的任何对象.

该函数看起来像这样:

static Node* findMatchingNode(const Node& root, const SomeFilterData& d);

struct Node {
   Node* left;
   Node* right;
};
Run Code Online (Sandbox Code Playgroud)

该函数可以返回树中的根或任何对象,也可以不返回任何对象.很明显,与给定声明相比,我必须在某处执行const_cast,在大多数情况下这是禁止的.

函数是否可以保证constness并同时允许任何人修改其输出?

编辑.我没有明确说明,我的函数确实没有修改树中的任何节点,也没有创建新的Node,它是纯函数.我想在const那里总是有限定符,告诉每个人该功能不会修改任何东西

编辑.后面的潜在问题是,在函数执行期间(并且仅在函数内部)没有强制输出常量的情况下,没有合法的方式来表达输入的常量.

Bau*_*gen 7

与往常一样,您无法修改const数据,因为它是常量.特别是:

尽管const_cast可以从任何指针或引用中删除constness或volatile,但是使用结果指针或引用来写入声明为const的对象或访问声明为volatile的对象会调用undefined行为.

(从这里)

因此,如果指向const输入参数root 的指针是一个明智的结果,那么返回类型也应该是const.无论如何你应该非常小心返回指针:截至目前,你的函数可以返回指向临时指针的指针!

所以最好返回一个boost::optional<Node>或一个std::optional<Node>(如果后者使它成为C++ 17并且你使用该标准).

如果您的函数仅对可修改的输入有意义root(例如,如果结果必须是可修改的结果可以是地址root),请将其const放入声明中.这也可以防止输入root是暂时的.


对于潜在的XY问题,最有可能是最干净的解决方案:

如果它适合你的用例(我发现这非常不可能的,事实并非如此),最可能的甚至更好的选择是在如树或列表的可重复的数据结构定义的算法(无论你Node是一个节点)和然后,如果不存在这样的节点,则将迭代器返回到匹配节点或者过去的结束迭代器(相对于高级结构).

至于const-vs.-non const讨论:使用iterator选项,你可以通过在高级结构上获取非const迭代器和const &参考的参数来区分高级结构的constness 和你比较的参考节点输入节点(临时现在不会有问题).

从我的问题中可以看出,您的功能甚至可以替换为std::find_if.那么你首先不会遇到这个问题.


Moo*_*uck 6

你的代码不是const-correct,它会删除const.这就是为什么你遇到"必需的"常量问题的原因.不要这样做:

static const Node* findMatchingNode(const Node& root, const SomeFilterData& d);
Run Code Online (Sandbox Code Playgroud)

你可以指出的是,你可能想从另一个函数调用这个函数确实修改节点,因此希望非const的结果.因此,这应该是一个具有完全不同签名的新功能:

static Node* findMatchingNode(Node& root, const SomeFilterData& d);
Run Code Online (Sandbox Code Playgroud)

您可能会指出它们具有相同的主体,并且存在DRY原则(DRY =不重复自己=没有复制粘贴的代码).是的,所以这里只需要一个快捷方式:const_cast.我认为在这种情况下它是正常的,因为它的唯一目的是共享代码,而且很明显它并没有违反任何const-correctness原则.

//This function does not modify anything
static Node* findMatchingNode(Node& root, const SomeFilterData& d) {
    return const_cast<Node*>(findMatchingNode(const_cast<const Node&>(root),d));
}
Run Code Online (Sandbox Code Playgroud)

Loki Asari建议添加findMatchingNodeCommon()两个版本的findMatchingNode()调用的第三个私有函数.那么你可以减少一个const_cast.如果你想变得极端,那么你可以findMatchingNodeCommon()模仿,然后全部const_cast消失.我认为这不值得打扰,但他们是非常有效的意见,所以值得一提.

  • 我个人会添加第三个私有函数`findMatchingNodeCommon()`,这两个版本的`findMatchingNode()`调用.然后你可以减少一个`const_cast`.如果你想变得极端,你可以使`findMatchingNodeCommon()`模板化,然后所有const_casts消失. (2认同)