【问题标题】:Invalid initialization of reference引用初始化无效
【发布时间】:2021-05-04 12:11:28
【问题描述】:

我有一个看起来像这样的模板类

namespace binary_search_tree {

template <typename T> 
class binary_tree {

private:
    T d;
    binary_tree<T> *l, *r;

public:
    binary_tree(T d) : d(d), l(nullptr), r(nullptr)
    {}
    
    void insert(T d) {
        binary_tree<T>* branch = new binary_tree<T>(d);
        if(d <= this->d) {
            this->l = branch;           
        } else {
            this->r = branch;
        }
    }
    
    const T data() const {
        return d;
    }
    
    const binary_tree<T>* left() const {
        return l;
    }
    
    const binary_tree<T>* right() const {
        return r;
    }

};

}

我有一个 test.cpp 文件,用于测试我的课程

#include "binary_search_tree.h"
#include "test/catch.hpp"
#include <vector>

// test data version: 1.0.0

template<typename T>
using tree_ptr = typename std::unique_ptr<binary_search_tree::binary_tree<T>>;

template<typename T>
static void test_leaf(const tree_ptr<T> &tree, 
                      const T& data, bool has_left, bool has_right)
{
    REQUIRE(data == tree->data());                  //        ***************
    REQUIRE((bool) tree->left() == has_left);       // <----  *** problem ***
    REQUIRE((bool) tree->right() == has_right);     //        ***************
}

template<typename T>
static tree_ptr<T> make_tree(const std::vector<T> &data)
{
    if (data.empty())
        return tree_ptr<T>(nullptr);
    
    auto data_iter = data.begin();
    auto tree = tree_ptr<T>(new binary_search_tree::binary_tree<T>(*data_iter));
    ++data_iter;

    for (; data_iter != data.end(); ++data_iter)
    {
        tree->insert(*data_iter);
    }

    return tree;
}

TEST_CASE("data_is_retained")
{
    auto tested = make_tree<uint32_t>({4});
    test_leaf<uint32_t>(tested, 4, false, false);
}


TEST_CASE("smaller_number_at_left_node")
{
    auto tested = make_tree<uint32_t>({4, 2});

    test_leaf<uint32_t>(tested, 4, true, false);
    test_leaf<uint32_t>(tested->left(), 2, false, false);
}

TEST_CASE() 函数来自一个为测试而设计的单独头文件。

问题源于在 test_leaf() 函数中调用 left() 和 right() 时。

编译器说

invalid initialization of reference of type ‘tree_ptr<unsigned int>&’ {aka ‘const 
std::unique_ptr<binary_search_tree::binary_tree<unsigned int>, 
std::default_delete<binary_search_tree::binary_tree<unsigned int> > >&’} from expression of 
type ‘binary_search_tree::binary_tree<unsigned int>*’

我不确定如何使这些类型匹配。我尝试过以各种方式返回参考,但这似乎让事情变得更糟。我应该返回一个 unique_ptr 吗?我对 default_delete 是什么感到困惑。在我看来,我应该返回某种引用而不是指针。我不确定如何在课堂上安全地做到这一点。

【问题讨论】:

  • this-&gt;l = &amp;branch; = 灾难的秘诀。分配一个非常临时的自动对象的地址。到什么应该是动态数据结构模型。 this-&gt;r = &amp;branch 也是如此。在离开branch 的周围范围的那一刻,该对象不再存在,留下一个悬空指针。
  • 编译器错误还有吗?
  • 注意:在传递 'void test_leaf(tree_ptr&, const T&, bool, bool) 的参数 1 [with T = unsigned int; tree_ptr = std::unique_ptr<:binary_tree int>, std::default_delete<:binary_tree int> > >]'
  • @WhozCraig 我应该完全避免使用指针吗?
  • 显然,在您的最后一个测试中,您不能同时对 test_left 的调用进行编译,因为对 left 的调用返回一个指针,而在第一个类中,您传递了一个对象。

标签: c++ pointers templates


【解决方案1】:

您的问题在这一行:

test_leaf<uint32_t>(tested->left(), 2, false, false);

binary_tree&lt;T&gt;::left 返回一个指向树的左子树的原始的、非拥有的指针,但 test_leaf 需要一个对 std::unique_ptr&lt;binary_tree&lt;T&gt;&gt; 的引用。

这里的解决方案是将test_leaf 改为接受原始指针或引用:

template<typename T>
static void test_leaf(binary_search_tree::binary_tree<T>& tree,
                      const T& data, bool has_left, bool has_right)
{
    REQUIRE(data == tree.data());
    REQUIRE(static_cast<bool>(tree.left()) == has_left);
    REQUIRE(static_cast<bool>(tree.right()) == has_right);
}

(注意tree 的类型确实应该是const 限定的,但是您的binary_tree 类模板不是const-正确到足以使其现在实际工作)

然后更改所有调用test_leaf 的任何类型指针的位置,以改为传递对基础对象的引用。例如:

test_leaf<uint32_t>(tested, 4, true, false);
test_leaf<uint32_t>(tested->left(), 2, false, false);

会变成

test_leaf<uint32_t>(*tested, 4, true, false);
test_leaf<uint32_t>(*tested->left(), 2, false, false);

一般来说,不承担指向对象的任何所有权的函数应该接受指向智能指针拥有的对象的引用或原始指针。传递对智能指针本身的引用不会增加任何安全性,并且不必要地将函数的使用限制为仅由特定类型的智能指针拥有的动态分配的对象。

【讨论】:

  • 假设我不想更改测试文件并且我将我的方法设为 const,我该如何解决这个问题?
  • 您可以将binary_treelr 成员更改为std::unique_ptr&lt;binary_tree&gt;s 而不是原始指针(无论如何您应该这样做)并拥有left 和@ 987654339@ 返回 (const) 对那些 unique_ptrs 的引用。我不确定您为什么要这样做。 test_leaf 没有什么要求它的参数是一个智能指针(或者完全引用一个动态分配的对象)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-18
  • 2020-06-12
  • 2023-03-06
  • 2014-03-23
  • 2015-01-26
  • 1970-01-01
相关资源
最近更新 更多