用reference_wrapper本地初始化向量

Initializing vector with reference_wrapper's locally

本文关键字:初始化 向量 wrapper reference      更新时间:2023-10-16

我想从标准容器使用许多与继承相关的类型(std::reference_wrapper是此类容器AFAIU的正确值类型(。但是,我不明白,当插入到映射中的引用的值不是全局变量时,如何初始化这样的容器。例如:

#include <iostream>
#include <vector>
#include <functional>
using namespace std;
struct I
{
virtual void print() = 0;
};
struct S1: public I
{
void print() override
{
cout << "S1 " << i << endl;
}
int i{};
};
struct S2: public I
{
void print() override
{
cout << "S2 " << f << endl;
}
float f{};
};
std::vector<reference_wrapper<I>> v;
void init()
{
S1 x{};
S2 y{};
v.emplace_back(x);
v.emplace_back(y);
}
int main()
{
init();
v[1].get().print();
return 0;
}

这样可以编译,但是我在运行时遇到一些内存损坏。初始化std::reference_wrappers 容器的正确方法是什么?

不能引用函数本地对象。 一旦函数退出,这些本地对象就会被销毁,你在向量中留下悬而未决的引用。 要解决此问题,您可以做的是切换到使用std::unique_ptr<I>std::make_unique动态分配要存储在矢量中的对象。std::unique_ptr将管理内存,一旦向量被销毁,它将破坏向量中的std::unique_ptr,它们将依次删除为保存对象而获取的内存。 那会给你

#include <iostream>
#include <vector>
#include <functional>
#include <memory>
using namespace std;
struct I
{
virtual void print() = 0;
};
struct S1: public I
{
void print() override
{
cout << "S1 " << i << endl;
}
int i{};
};
struct S2: public I
{
void print() override
{
cout << "S2 " << f << endl;
}
float f{};
};
std::vector<unique_ptr<I>> v;
void init()
{
v.emplace_back(std::make_unique<S1>()); // creates a defaulted S1 in the unique_ptr
v.emplace_back(std::make_unique<S2>()); // creates a defaulted S2 in the unique_ptr
}
int main()
{
init();
v[1]->print(); // or (*v[1]).print()
return 0;
}

您面临的问题是您的对象S1 xS2 yinit函数结束时被销毁。所以,在init()末尾,你的向量v包含对任何内容的引用。因此,当尝试调用print()时,您会得到一个segmentation fault

以类似的方式,考虑以下代码:

int& get_i()
{
int i = 1;
return i;
}
int main()
{
std::cout << get_i() << std::endl; // segmentation fault
return 0;
}

这也会产生一个segmentation fault,因为get_i()返回对局部变量的引用(如果get_i(),则在最后销毁(。

您可以改用用户std::unique_ptr,如其中一条评论中所述。