在本地用 reference_wrapper 初始化向量
Initializing vector with reference_wrapper's locally
我想从标准容器中使用许多与继承相关的类型(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_wrapper
s 容器的正确方法是什么?
您不能引用函数局部对象。一旦函数退出,这些局部对象就会被销毁,你会在向量中留下悬空引用。要解决此问题,您可以改用 std::unique_ptr<I>
和 std::make_unique
来动态分配要存储在向量中的对象。 std::unique_ptr
将管理内存,一旦 vector 被销毁,它将销毁 vector 中的 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 x
和 S2 y
在 init
函数结束时被销毁。因此,在 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()
returns 对局部变量的引用(如果 get_i()
则在最后被销毁)。
您可以改用 std::unique_ptr
,如评论之一所述。
我想从标准容器中使用许多与继承相关的类型(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_wrapper
s 容器的正确方法是什么?
您不能引用函数局部对象。一旦函数退出,这些局部对象就会被销毁,你会在向量中留下悬空引用。要解决此问题,您可以改用 std::unique_ptr<I>
和 std::make_unique
来动态分配要存储在向量中的对象。 std::unique_ptr
将管理内存,一旦 vector 被销毁,它将销毁 vector 中的 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 x
和 S2 y
在 init
函数结束时被销毁。因此,在 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()
returns 对局部变量的引用(如果 get_i()
则在最后被销毁)。
您可以改用 std::unique_ptr
,如评论之一所述。