C++指针的引用是否为空?

C++指针的引用是否为空?,c++,class,pointers,generics,reference,C++,Class,Pointers,Generics,Reference,给定以下代码: template<class S, class T> class node { public: S key; T value; node<S, T> *right_node, *left_node, *parent_node, *nearest_right_node, *nearest_left_node; int height; public: template<typename, typename>

给定以下代码:

template<class S, class T>
class node {
public:
    S key;
    T value;
    node<S, T> *right_node, *left_node, *parent_node, *nearest_right_node, *nearest_left_node;
    int height;

public:
    template<typename, typename> friend
    class avl_tree;

    node() = default;

    node(const S *key, const T *value, node<S, T> *right_node = nullptr, node<S, T> *left_node = nullptr,
         node<S, T> *parent_node = nullptr, node<S, T> *nearest_right_node = nullptr,
         node<S, T> *nearest_left_node = nullptr) : key(*key),
                                                    value(*value),
                                                    right_node(right_node),
                                                    left_node(left_node),
                                                    parent_node(parent_node),
                                                    nearest_right_node(nearest_right_node),
                                                    nearest_left_node(nearest_left_node),
                                                    height(0) {
    }

    ~node() = default;
};

我可以调用update\u xnull\u ptr吗?代码中的问题归结为:

void foo(int* x) {
   int y = *x;
}
将nullptr传递给foo将导致未定义的行为,因为您不应取消对nullptr的引用

使用引用是可能的,但不会改变这一事实:

void bar(int*& x) {
    int y = *x;
}
这是通过引用传递指针

int a;
int* p = &a;
bar(p);
现在,条中的x是指向a的指针的引用。但是,您不能将空指针传递给bar,因为bar正在取消对指针的引用。某些恶意代码可能会执行以下操作:

int* p = nullptr;
bar(p);           // DO NOT DO THIS !!!
然后int y=*x;将调用未定义的行为

如果函数希望始终获取有效对象,则应通过引用获取该对象:

void foo_bar(int& x) {
    int y = x;   // no danger, all fine
}
引用不能引用任何内容。必须对其进行初始化:

int& x; // ERROR !
int y;
int& z = y;  // OK, z refers to y
另一方面,指针并不总是指向有效的指针对象:

int* p;       // not initialized, no (big) problem
p = nullptr;  // still not pointing to an int
int q;
p = &q;       // now p points to an int
引用不能引用nothing,这就是为什么当nothing不是有效参数时,您应该更喜欢引用而不是指针。在您的情况下,您总是需要*值才有效,因此值总是必须指向S,您应该使用引用来避免上述问题

关于您的更新:

我可以调用update\u xnull\u ptr吗


不,你不能。nullptr不是int。对int的引用总是引用int。

代码中的问题归结为:

void foo(int* x) {
   int y = *x;
}
将nullptr传递给foo将导致未定义的行为,因为您不应取消对nullptr的引用

使用引用是可能的,但不会改变这一事实:

void bar(int*& x) {
    int y = *x;
}
这是通过引用传递指针

int a;
int* p = &a;
bar(p);
现在,条中的x是指向a的指针的引用。但是,您不能将空指针传递给bar,因为bar正在取消对指针的引用。某些恶意代码可能会执行以下操作:

int* p = nullptr;
bar(p);           // DO NOT DO THIS !!!
然后int y=*x;将调用未定义的行为

如果函数希望始终获取有效对象,则应通过引用获取该对象:

void foo_bar(int& x) {
    int y = x;   // no danger, all fine
}
引用不能引用任何内容。必须对其进行初始化:

int& x; // ERROR !
int y;
int& z = y;  // OK, z refers to y
另一方面,指针并不总是指向有效的指针对象:

int* p;       // not initialized, no (big) problem
p = nullptr;  // still not pointing to an int
int q;
p = &q;       // now p points to an int
引用不能引用nothing,这就是为什么当nothing不是有效参数时,您应该更喜欢引用而不是指针。在您的情况下,您总是需要*值才有效,因此值总是必须指向S,您应该使用引用来避免上述问题

关于您的更新:

我可以调用update\u xnull\u ptr吗

不,你不能。nullptr不是int。对int的引用始终引用int。

您的节点类具有成员的key和T值,以及构造函数参数const S*key和const T*value,它们分别使用key*key和value*value初始化成员,将输入值复制到成员中

如果将nullptr传递给任一参数,则代码在取消引用nullptr时具有未定义的行为

没有理由让参数成为指针。它们应通过值传入:

样板 类节点{ 公众: S键; T值; ... 公众: ... 节点键,T值,…:键键,值,…{} //或者:nodeS key,T value,…:keystd::movekey,valuestd::movevalue,…{} ... }; 或通过常量引用:

void foo_bar(int& x) {
    int y = x;   // no danger, all fine
}
样板 类节点{ 公众: S键; T值; ... 公众: ... nodeconst S&key,const T&value,…:keykey,valuevalue,…{} ... }; 或通过右值引用:

void foo_bar(int& x) {
    int y = x;   // no danger, all fine
}
样板 类节点{ 公众: S键; T值; ... 公众: ... 节点&&key,T&&value,…:keystd::movekey,valuestd::movevalue,…{} ... }; 如果S或T被定义为指针类型,则可以传入nullptr作为要分配给键/值成员的值,例如:

node*n=新的node1,nullptr; t型; 节点*n=新节点1,&t; 但如果S和T不是指针类型,则不应将其作为指针传入:

t型; 节点*n=新节点1,t; t型; node*n=新node1,std::movet; node*n=新节点1,类型{}; 节点类具有成员的key和T值,以及构造函数参数const S*key和const T*value,它们分别使用key*key和value*value初始化成员,这将把输入值复制到成员中

如果将nullptr传递给任一参数,则代码在取消引用nullptr时具有未定义的行为

没有理由让参数成为指针。它们应通过值传入:

样板 类节点{ 公众: S键; T值; ... 公众: ... 节点键,T值,…:键键,值,…{} //或者:nodeS key,T value,…:keystd::movekey,valuestd::movevalue,…{} ... }; 或通过常量引用:

void foo_bar(int& x) {
    int y = x;   // no danger, all fine
}
样板 类节点{ 公众: S键; T值; ... 公众: ... nodeconst S&key,const T&value,…:keykey,valuevalue,…{} ... }; 或通过右值引用:

void foo_bar(int& x) {
    int y = x;   // no danger, all fine
}
样板 类节点{ 公众: S键; T值; ... 公众: ... 节点和键,T& &价值,…:keystd::movekey,valuestd::movevalue。。。{ } ... }; 如果S或T被定义为指针类型,则可以传入nullptr作为要分配给键/值成员的值,例如:

node*n=新的node1,nullptr; t型; 节点*n=新节点1,&t; 但如果S和T不是指针类型,则不应将其作为指针传入:

t型; 节点*n=新节点1,t; t型; node*n=新node1,std::movet; node*n=新节点1,类型{};
现在传递到构造函数中的键和值指针不能为null。如果是的话,你无论如何都会取消引用它们,并得到未定义的行为。你知道引用和指针之间的区别吗?这不是语言的一个模糊的角落,它的肉和土豆。我认为你可以从一个.key*键中获益。这个键总是错误的,没有if或but。更新是无效的。它不会编译。你不能以任何方式、形状或形式使用它。@n.“代词是m。你为什么说它总是错的?除非参数键是nullptr,否则它是ok ish。从代码无法通过审查的意义上讲是错误的,我同意您现在传递到构造函数中的键和值指针不能为null。如果是的话,你无论如何都会取消引用它们,并得到未定义的行为。你知道引用和指针之间的区别吗?这不是语言的一个模糊的角落,它的肉和土豆。我认为你可以从一个.key*键中获益。这个键总是错误的,没有if或but。更新是无效的。它不会编译。你不能以任何方式、形状或形式使用它。@n.“代词是m。你为什么说它总是错的?除非参数键是nullptr,否则它是ok ish。从某种意义上说,代码不会通过审查是错误的,我确实同意,谢谢,但这不是我的意思,我会的explain@whiteforce看到了吗?那么为什么在我的最后一个问题中,你和另一个家伙告诉我改变c'tor指向引用的指针?如果钥匙可以打开,那就没有意义了null@whiteforce这实际上是答案。看看barint*&x。原则上,您可以向它传递一个nullptr,然后x是对nullptr的引用,但只要在int y=*x行中取消对它的引用,它就会爆炸;这基本上就是你生活中发生的事情constructor@whiteforce谢谢,但这不是我的意思,我会的explain@whiteforce看到了吗?那么为什么在我的最后一个问题中,你和另一个家伙告诉我改变c'tor指向引用的指针?如果钥匙可以打开,那就没有意义了null@whiteforce这实际上是答案。看看barint*&x。原则上,您可以向它传递一个nullptr,然后x是对nullptr的引用,但只要在int y=*x行中取消对它的引用,它就会爆炸;这基本上就是你生活中发生的事情constructor@whiteforce参见编辑