繁体   English   中英

如果方法没有改变参数,为什么我不能把它作为const传递?

[英]If the method doesn't change the parameter, why can't I pass it as const?

我是一名学生,他仍然没有得到const参数。 我理解为什么这不起作用:

#include <stddef.h>

struct Node {

    int value;
    Node* next;
};

Node* cons(const int value, const Node * next) {

    Node * tmp = new Node();
    tmp->value = value;
    tmp->next = next;

    return tmp;
}

int main () {

    const Node * k;
    k = cons(1, NULL);

    Node * p;

    p = cons(2, k);

}

这是因为我通过给出地址来“抛弃”k的常数。

我通过标记参数“const”的意图是说我的方法不会直接改变节点。 就好像我要传入(Node * next)一样,我觉得不能保证我的方法不会取消引用该指针并弄乱节点。 也许这是愚蠢的,因为之后无法保证以后在const节点上我传递的指针不会通过新的指针来改变它。 看起来很奇怪:在这个方法缺点中,我所做的就是将一个新指针指向'next' - 我从未接触到下一个,只是指向 - 但这足以打破常量。

也许我只是低估了“常量”承诺的力量。

谢谢!

问题是你的next参数是const Node *类型(读取:指向常量Node对象的指针),而Node::next字段是Node *类型(指向非const Node对象的指针)。

这样做的时候

tmp->next = next;

您尝试使编译器获取指向const Node对象的指针,并将其指定给指向非const Node的指针。 如果这有效,那么绕过const就是一种简单的方法,因为突然之后人们可以通过解除引用tmp->next 修改next参数。

也许我只是低估了“常量”承诺的力量。

那么你做出的承诺是什么? 该函数获取指向Node的指针的副本 ,并承诺不允许对该Node进行任何修改。 承诺不是关于指针,它是Node * const (而且是无用的,因为它是通过值传递的,并且该级别的const从签名中删除),但关于指针, Node

为了提供一个现实生活中的例子,考虑到一个朋友在你度假期间提供给你的植物浇水,承诺(通常暗示)他不会从你的房子东西。 现在你复制一把钥匙并交给你的朋友,他自己制作钥匙的副本,并把它交给一个从未承诺不会抢劫你的第三方。 你认为你的朋友违背了他的诺言吗? 他的承诺有多强?

上面的代码具有完全相同的模式, cons承诺你可以给它一个指向Node的指针的副本,并且它不允许它被修改,但是只要你输入代码,他就会将指针复制到一个不同的指针,不对Node做任何承诺,然后将副本交给任何可能感兴趣的人。

如果T是任何类型,则有两个相关的指针类型, T *const T *

通过获取类型为T某个对象的“地址”,您可以获得本质上的指针。 指针的类型取决于对象的常量:

T x;
const T y;

T * p1       = &x; // OK, &x is T*
// T * p2    = &y; // Error!
const T * q1 = &y; // OK, &y is const T *
const T * q2 = &x; // also fine

因此,如果我们有一个可变对象,指向它的指针自然是一个指向可变的指针。 但是,如果我们只有一个常量对象,那么指针只能是一个指向常量的指针。 因为我们总是可以将可变对象视为常量对象(只是不要触摸),所以指向变量的指针总是可以转换为指向const的指针,就像q2的情况一样。

这就是你的k发生的事情:它是一个const T * (用T = Node ),我们给它分配一个T *的值,这很好,因为我们只是忽略了我们可以改变T的事实我们喜欢。

[在现实生活中,我们通常使用常量引用而不是平坦的常量对象,但您可以将它们视为同一事物(因为引用只是对象的别名 ,并且在功能上与对象本身相同)。

现在你可能会把所有这些const与对象本身的const混淆:就像之前我们有xy ,一个可变和一个常量一样,我们可以将相同的逻辑应用于指针类型本身:让我们定义P = T * ,和Q = const T * 然后上面的代码,我们所有的对象都是可变对象P p1, p2; Q q1, q2; P p1, p2; Q q1, q2; 也就是说,我们总是可以任何指针更改为指向其他位置: q2 = &z; 没问题。 这是你在做什么,以k当你重新分配它。

当然我们也可以声明这些指针的常量版本: const P p3 = &x; const Q q3 = &y; const P p3 = &x; const Q q3 = &y; 这些不能被重新分配(毕竟是常量)。 如果按照人们通常的做法将其拼写为T ,则会有点响亮:

T       * p3 const = &x;
const T * q3 const = &y;

我希望这不会造成比解决更多的混乱!

也许这是愚蠢的,因为之后无法保证以后在const节点上我传递的指针不会通过新的指针来改变它。 看起来很奇怪:在这个方法缺点中,我所做的就是将一个新指针指向'next' - 我从未接触到下一个,只是指向 - 但这足以打破常量。

这不只是你指出,这是你与非指向const指针。 如果你让Node::entry成为一个const Node* ,事情应该可行。

当然,这限制了您在操作列表时可以执行的操作。

在C ++中实际上有两种不同形式的const :“诚实 - 真正的const ”和“就你现在所关注的const而言”。 大多数时候你会处理第二种,就像在例子中一样。 但是,你的程序需要两种形式的正常工作constconst正确:

int main()
{
    const Node n = { 5, NULL };
    Node* p = cons(6, &n);
}

n (或指向n的指针)抛弃const是未定义的行为,并且cons必须尊重它。 我还要提一下,我相信你的一部分假设是你认识到你的函数可以修改const Node* ,但是认为由于麻烦的赋值是方法的最后一行,编译器应该认识到它实际上并没有哪里不对了。 我不知道C ++中的任何规则都说“做X是违法的,除非你把它作为函数的最后一行。” 无论是在函数中的第一个还是最后一个,都不允许赋值。

您可能能够获得所需的设计并具有const正确性。 举例来说,你允许超载cons采取任何一个const Node*Node*和建立的名单const或非const相应元素。 如果我更了解你想做什么,我可能会对如何到达那里有一个更好的答案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM