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
(每次通话后都不同)
解决方案
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>
从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>>
推荐阅读
- android - Circular Avatar ImageView with Text Layover at the bottom
- java - 使用 OAuth 到 Azure AD 的 Java WebApp - 获取个人资料图片?
- java - Gradle for Android:为什么 javaexec 不选择我的类路径?
- php - Laravel whereIn in array
- firebase - Can't select Firebase AB Testing Activation event nor Goal metric event
- python - 如何编写测量每行(对象)频率的函数 - Python
- openedge - 将 FOR EACH 中的行添加到 TEMP-TABLE
- swift - FCM 适用于 Firebase v3.4.1,但不适用于 v5.8.1
- ffmpeg - Crop, Resize and Cut all in one command - FFMPEG
- amazon-web-services - How to set DHCP Options Set via AWS SDK