首先,我想说的是在此示例中必须使用对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
(每次通话后都不同)
答案 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>>
。