C++ 使用引用_包装器'初始化向量;在当地

C++ 使用引用_包装器'初始化向量;在当地,c++,polymorphism,containers,reference-wrapper,C++,Polymorphism,Containers,Reference Wrapper,我想从标准容器中使用许多与继承相关的类型(std::reference\u wrapper是这种容器的合适值类型,AFAIU)。但是,我不明白,当值(插入到映射中的引用)不是全局变量时,如何初始化这样的容器。例如: #include <iostream> #include <vector> #include <functional> using namespace std; struct I { virtual void print() = 0;

我想从标准容器中使用许多与继承相关的类型(
std::reference\u 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;
结构一
{
虚空打印()=0;
};
结构S1:公共I
{
void print()覆盖
{

cout您不能拥有对函数本地对象的引用。一旦函数退出,这些本地对象将被销毁,并且向量中的引用将处于悬挂状态。要解决此问题,您可以切换到使用
std::unique_ptr
std::make_unique
动态分配您要创建的对象ore在向量中。
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;
}
#包括
#包括
#包括
#包括
使用名称空间std;
结构一
{
虚空打印()=0;
};
结构S1:公共I
{
void print()覆盖
{

cout您不能拥有对函数本地对象的引用。一旦函数退出,这些本地对象将被销毁,并且向量中的引用将处于悬挂状态。要解决此问题,您可以切换到使用
std::unique_ptr
std::make_unique
动态分配您要创建的对象ore在向量中。
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;
}
#包括
#包括
#包括
#包括
使用名称空间std;
结构一
{
虚空打印()=0;
};
结构S1:公共I
{
void print()覆盖
{

cout您面临的问题是对象
s1x
S2 y
init
函数的末尾被销毁。因此,在
init()
的末尾,向量
v
不包含任何引用。因此,在尝试调用
print()时
,则会出现
分段错误

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

int& get_i()
{
    int i = 1;
    return i;
}

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

std::cout您面临的问题是,对象
s1x
S2 y
init
函数的末尾被销毁。因此,在
init()
的末尾,向量
v
不包含任何引用。因此,在尝试调用
print()时
,则会出现
分段错误

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

int& get_i()
{
    int i = 1;
    return i;
}

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

std::coutstd::reference_包装器
意味着将引用存储在可复制和可分配的对象中,这些对象可以存储在容器中,如
std::vector
。但是
reference_包装器
不拥有引用对象,因此其他对象必须拥有它

引用对象的生命周期应长于
reference\u wrapper
,因此OP代码中的问题是
init()
将函数本地对象的引用放置到
v
。这些对象的生命周期在返回
init()
时结束。可以避免:

#include <iostream>
#include <vector>
#include <functional>

struct I
{
    virtual void print() = 0;
};

struct S1: public I
{
    S1(int in) 
        : I(), i(in)
    { }

    void print() override
    {
        std::cout << "S1 " << i << std::endl;
    }
    int i;
};

struct S2: public I
{
    S2(float fn) 
        : I(), f(fn)
    { }

    void print() override
    {
        std::cout << "S2 " << f << std::endl;
    }
    float f;
};

// x owns couple S1 objects
S1 x[] = {1,3,5,7}; 
// y owns couple S2 objects
S2 y[] = {2,4,6,8};
// v can refer to S1 and S2 objects owned by others
std::vector<std::reference_wrapper<I>> v; 

// makes v to refer all objects in x and y
void init()
{
    copy(&x[0], &x[sizeof x / sizeof x[0]], back_inserter(v));
    copy(&y[0], &y[sizeof y / sizeof y[0]], back_inserter(v));
}

int main()
{
    init();
    for (auto e : v)
    {
        e.get().print();
    }
    return 0;
}
#包括
#包括
#包括
结构一
{
虚空打印()=0;
};
结构S1:公共I
{
S1(整数英寸)
:I(),I(in)
{ }
void print()覆盖
{

std::coutstd::reference_包装器
意味着将引用存储在可复制和可分配的对象中,这些对象可以存储在容器中,如
std::vector
。但是
reference_包装器
不拥有引用对象,因此其他对象必须拥有它

引用对象的生命周期应长于
reference\u wrapper
,因此OP代码中的问题是
init()
将函数本地对象的引用放置到
v
。这些对象的生命周期在返回
init()
时结束。可以避免:

#include <iostream>
#include <vector>
#include <functional>

struct I
{
    virtual void print() = 0;
};

struct S1: public I
{
    S1(int in) 
        : I(), i(in)
    { }

    void print() override
    {
        std::cout << "S1 " << i << std::endl;
    }
    int i;
};

struct S2: public I
{
    S2(float fn) 
        : I(), f(fn)
    { }

    void print() override
    {
        std::cout << "S2 " << f << std::endl;
    }
    float f;
};

// x owns couple S1 objects
S1 x[] = {1,3,5,7}; 
// y owns couple S2 objects
S2 y[] = {2,4,6,8};
// v can refer to S1 and S2 objects owned by others
std::vector<std::reference_wrapper<I>> v; 

// makes v to refer all objects in x and y
void init()
{
    copy(&x[0], &x[sizeof x / sizeof x[0]], back_inserter(v));
    copy(&y[0], &y[sizeof y / sizeof y[0]], back_inserter(v));
}

int main()
{
    init();
    for (auto e : v)
    {
        e.get().print();
    }
    return 0;
}
#包括
#包括
#包括
结构一
{
虚空打印()=0;
};
结构S1:公共I
{
S1(整数英寸)
:I(),I(in)
{ }
void print()覆盖
{

std::cout如果您需要
v
来拥有存储在其中的实例,那么您需要它是
std::vector
并通过
std::make_unique()使用动态分配
。如果需要
v
来拥有存储在其中的实例,则需要将其作为
std::vector
并通过
std::make_unique()使用动态分配。