【问题标题】:C++ can a reference of pointer take null?C++ 指针的引用可以为空吗?
【发布时间】:2021-03-15 13:43:30
【问题描述】:

给定以下代码:

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;
};

我可以用引用替换 c'tor 中 valuekey 的指针,并且仍然可以给 keyvalue 一个 nullptr 值吗? (例如,如果 S 是 int*)?

更新:

int* x;

    void update_x(int &new_x)
    {
        x=new_x;
    }

我可以打电话给update_x(null_ptr)

【问题讨论】:

  • 您现在传递给构造函数的keyvalue 指针已经 不能为空。如果是,您无论如何都会取消引用它们并获得未定义的行为。
  • 你知道引用和指针的区别吗?这不是语言的一个不起眼的角落,它的肉和土豆。我认为您可以从good C++ book 中受益。
  • key(*key) 这总是错的,没有如果或但是。
  • 更新完全无效。它不会编译。您不能以任何方式、形状或形式使用它。
  • @n.'pronouns'm。为什么你说它总是错的?除非参数keynullptr,否则没问题。 “错误”是指代码无法通过审核,我同意

标签: c++ class pointers generics reference


【解决方案1】:

您的代码中的问题归结为:

void foo(int* x) {
   int y = *x;
}

nullptr 传递给foo 将导致未定义的行为,因为您不应取消引用nullptr

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

void bar(int*& x) {
    int y = *x;
}

这是通过引用传递指针。

int a;
int* p = &a;
bar(p);

现在bar 中的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

引用不能引用任何内容,这就是为什么当“无”不是有效参数时,您应该更喜欢引用而不是指针。在您的情况下,您始终要求 *value 有效,因此 value 始终必须指向 S 并且您应该使用引用来避免上述问题。


关于您的更新:

int* x;

    void update_x(int &new_x)
    {
        x=new_x;
    }

我可以调用 update_x(null_ptr)

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

【讨论】:

  • 谢谢,但这不是我要解释的意思
  • 那么为什么在我的最后一个问题中你和另一个人告诉我将 c'tor 指针更改为引用?如果 key 可以为空,那就没有意义了
  • @whiteforce 实际上在答案中。看看bar(int*&amp; x)。原则上你可以传递一个nullptr 然后x 是对nullptr 的引用,但是一旦你取消引用它就会爆炸(在int y = *x; 行中(这基本上就是你的构造函数中发生的事情) )
  • 实际上空引用上的右值到左值转换是非法的。空引用的创建(通过取消引用空指针)不是未定义的行为,只要它仍然是未使用的左值。
  • @largest_prime_is_463035818 在您的回答中,void bar(int*&amp; x) ... int a; bar(&amp;a); 无法编译,因为无法绑定引用:“error: cannot bind non-const lvalue reference of type 'int*& ' 到类型为 'int'*" 的右值它必须更像这样:int a; int *b = &amp;a; bar(b);
【解决方案2】:

您的node 类有成员S keyT value,构造函数参数const S *keyconst T *value 分别使用key(*key)value(*value) 初始化成员,这将复制 成员的输入值。

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

参数根本没有理由是指针。它们应该通过按值传递:

template<class S, class T>
class node {
public:
    S key;
    T value;
    ...

public:
    ...

    node(S key, T value, ...) : key(key), value(value), ... { }
    // or: node(S key, T value, ...) : key(std::move(key)), value(std::move(value)), ... { }

    ...
};

通过常量引用

template<class S, class T>
class node {
public:
    S key;
    T value;
    ...

public:
    ...

    node(const S& key, const T& value, ...) : key(key), value(value), ... { }

    ...
};

通过右值引用

template<class S, class T>
class node {
public:
    S key;
    T value;
    ...

public:
    ...

    node(S&& key, T&& value, ...) : key(std::move(key)), value(std::move(value)), ... { }

    ...
};

如果ST 被定义为指针类型,那么nullptr 可以作为 传递给key/value 成员,例如:

node<int, type*> *n = new node<int, type*>(1, nullptr);
type t;
node<int, type*> *n = new node<int, type*>(1, &t);

但是如果ST不是指针类型,就不应该作为指针传入:

type t;
node<int, type> *n = new node<int, type>(1, t);
type t;
node<int, type> *n = new node<int, type>(1, std::move(t));
node<int, type> *n = new node<int, type>(1, type{});

【讨论】:

    猜你喜欢
    • 2021-12-14
    • 2019-11-07
    • 1970-01-01
    • 2011-05-27
    • 1970-01-01
    • 1970-01-01
    • 2011-06-27
    • 2021-07-25
    • 1970-01-01
    相关资源
    最近更新 更多