首页 > 解决方案 > 向量中的引用失去了价值

问题描述

首先我想说,在这个例子中使用对 Value 的引用是必须的。

所以,我有一棵树(为简单起见,这是一个只有一个子节点的树,这段代码不是我原来的任务,但问题是一样的),我想在其中存储值。

要导出值,我必须使用 std::pairs 的向量,带有键和对值的引用。我试图在递归函数'col'中做到这一点,以一个接一个地推回这些值。

我的问题是,最终值不同。当我切换对指针的引用时,它工作正常。但正如我所说,它必须是参考。

我不明白,在这种情况下,这两者之间有什么区别?它们都应该指向堆上的内存,并且该地址应该保持不变,对吗?这是代码:

#include <memory>
#include <vector>
#include <iostream>

template <typename Value>
class Tree {
public:
    class Node {
        std::unique_ptr<Value> value;
        std::unique_ptr<Node> child;
    public:
        friend Tree;
        Node(const Value i) : value(std::make_unique<Value>(i)) {}
        Value* getvalue() { return value.get();}
        Node* getchild() { return child.get();}
    };

    const std::vector<std::pair<std::string,const Value&>> collect() {
        std::vector<std::pair<std::string,const Value&>> list;
        col(list, root.get());
        return list;
    }

    void col(std::vector<std::pair<std::string,const Value&>>& list, Node* node) {
        list.push_back(std::make_pair("k", *node->getvalue()));
        if (node->getchild() != nullptr) {
            col(list, node->getchild());
        }
    }

    void addNode(const Value i) {
      add(root.get(), i);
    }

    Node* getroot() { return root.get();}

private:
    std::unique_ptr<Node> root = std::make_unique<Node>(0);

    void add(Node* node, const Value& i) {
        if (node->getchild() == nullptr) {
            node->child = std::make_unique<Node>(i);
        } else {
            add(node->getchild(), i);
        }
    }
};

int main() {
    Tree <int>t;
    t.addNode(1);
    t.addNode(2);
    t.addNode(3);
    auto a = t.collect();
    for (auto p : a) {
        std::cout << p.first << " " << p.second << "\n";
    }
}

输出是:

k 0
k -424282688
k -424282688
k 0

(每次通话后都不同)

标签: c++

解决方案


list.push_back(std::make_pair("k", *node->getvalue()));

std::make_pairstd::pair从其函数参数推导出模板参数,并且从不使用它们的引用类型(注意std::decay链接页面上的部分)。所以返回类型make_pairstd::pair<const char*, Value>,实例化为std::pair<const char*, int>。这对的int second;成员是*node->getvalue().

vector<T>::push_back(T&&)需要一个实际元素类型的参数,这里是T = std::pair<std::string, const int&>. std::pair<const char*, int>从to有一个隐式转换std::pair<std::string, const int&>std::string first;成员是从原始字符串指针构造的,并且该const int& second;成员绑定到输入对的成员。

但这std::pair<const char*, int>是一个临时的,所以一旦语句结束,复制和引用值的生命周期就结束了。下次您尝试使用参考时,砰。

而不是使用make_pair,指定您需要的确切类型:

list.push_back(std::pair<std::string, const Value&>("k", *node->getvalue()));

或者

list.push_back(decltype(list)::value_type("k", *node->getvalue()));

或将 ausing OutPairType = std::pair<std::string, const Value&>;放在类定义中并使用它,而不是在其他地方输入它。

另请注意,当 astd::pair具有引用成员时,就像任何具有引用成员的结构的默认行为一样,operator=复制和移动赋值运算符将复制或移动引用的对象。他们不会(也不能)更改引用成员以引用与右侧成员相同的对象,就像指针赋值一样。std::vector有时会使用operator=value_type(虽然不在push_back)。您可能要考虑改用。std::pair<std::string,std::reference_wrapper<const Value>>


推荐阅读