向量中的引用失去了价值

时间:2018-12-16 13:12:08

标签: c++

首先,我想说的是在此示例中必须使用对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

(每次通话后都不同)

1 个答案:

答案 0 :(得分:1)

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

std::make_pair从其函数参数推导std::pair的模板参数,并且从不为其使用引用类型(请注意链接页面上的std::decay部分)。因此,make_pair的返回类型为std::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>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()));

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

还要注意,当std::pair具有引用成员时,例如具有引用成员的任何结构的默认行为,operator=复制和移动分配操作符将复制或移动被引用的对象。它们不会(也不能)将引用成员更改为引用与右侧成员相同的对象,就像指针分配一样。并且std::vector有时会使用其operator=中的value_type(尽管不在push_back中)。您可能要考虑改用std::pair<std::string, std::reference_wrapper <const Value>>