返回引用时的std :: vector :: emplace_back错误(C++ 17)

And*_* T. 2 c++ debugging g++ c++17

我一直试图追踪一个错误超过10个小时,到现在为止我开始认为这个错误不在我身边.但是,我觉得可能是我只是忘记或误解了某些东西.

我有一个类型为std :: vector的类成员,名为temp_materials,在构造函数内部(当temp_materials仍为空时),此代码运行:

    Material &stonewallbug = temp_materials.emplace_back(resource_lib.get_shader("DeferredGeometryShader"));
    stonewallbug.set_texture("texture_diffuse1", resource_lib.get_texture("StonewallDiffuse"));
    stonewallbug.set_texture("texture_specular1", resource_lib.get_texture("StonewallSpecular"));

    Material &containerbug = temp_materials.emplace_back(resource_lib.get_shader("DeferredGeometryShader"));
    containerbug.set_texture("texture_diffuse1", resource_lib.get_texture("ContainerDiffuse"));
    containerbug.set_texture("texture_specular1", resource_lib.get_texture("ContainerSpecular"));

    Material stonewall1 = temp_materials[0];
    Material container1 = temp_materials[1];

    Material stonewall2 = stonewallbug;
    Material container2 = containerbug;
Run Code Online (Sandbox Code Playgroud)

如果在复制过程中没有出错,那么stonewall1的内容应该等于stonewall2,容器1到容器2应该是正确的吗?

但是,然后我将所有这些插入到一个简单的向量中,其内容将在稍后呈现:

    // Using temp_materials[0]
    auto stonewall1node = SceneNode(stonewall1, resource_lib.get_mesh("Cube"));
    stonewall1node.set_transform(glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f)));
    m_scene_list.push_back(stonewall1node);

    // Using temp_materials[1]
    auto container1node = SceneNode(container1, resource_lib.get_mesh("Cube"));
    container1node.set_transform(glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 1.0f)));
    m_scene_list.push_back(container1node);

    // Using stonewallbug
    auto stonewall2node = SceneNode(stonewall2, resource_lib.get_mesh("Cube"));
    stonewall2node.set_transform(glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 1.0f, 0.0f)));
    m_scene_list.push_back(stonewall2node);

    // Using containerbug
    auto container2node = SceneNode(container2, resource_lib.get_mesh("Cube"));
    container2node.set_transform(glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 1.0f, 1.0f)));
    m_scene_list.push_back(container2node);
Run Code Online (Sandbox Code Playgroud)

现在,我希望有2个"容器"立方体相互堆叠,2个"石墙"立方体堆叠在一起,但这是我得到的结果:

结果1

但是,如果我将线路移动Material stonewall2 = stonewallbug;到stonewallbug和containerbug的创建之间,我会得到我期望的结果.

注意到这一点,我做了一个非常非常简单的C++程序:

#include <iostream>
#include <vector>
#include <string>


int main() {
    std::vector<std::string> strings;

    std::string& ref1 = strings.emplace_back("1");
    std::string& ref2 = strings.emplace_back("2");

    std::cout << "ref1: " << ref1 << std::endl;
    std::cout << "ref2: " << ref2 << std::endl;

    std::cout << "strings[0]: " << strings[0] << std::endl;
    std::cout << "strings[1]: " << strings[1] << std::endl;


    return 0;
}
Run Code Online (Sandbox Code Playgroud)

运行它时的结果是很多无意义的字符.但是,如果在安装ref2之前输出ref1,它会输出预期的结果.在这里,它说vector的emplace_back应该返回对插入元素的引用,但对我来说它似乎并不像它应该的那样工作.

我误解了什么,或者这只是g ++ 7.1中一个非常明显的错误?

编辑:我简直不敢相信我在这么明显的事情上花了这么多时间...... :)

Ker*_* SB 9

您必须小心容器元素的引用和迭代器.各种变异容器操作使引用和迭代器无效.详细信息因容器和操作而异,但是,对于std::vector所有插入操作(例如push_backemplace_back)以及除结束之外的任何其他操作的擦除,通常会使引用和迭代器无效(但请参阅下面的方法来避免这种情况).

因此,在以下代码中,

std::vector<T> v;

T & a = v.emplace_back(a, b, c);
T & b = v.emplace_back(x, y, z);
Run Code Online (Sandbox Code Playgroud)

第二次调用emplace_back使参考无效a.(通过无效引用访问对象具有未定义的行为.)

为避免a中的失效std::vector,请使用reservecapacity设施:

std::vector<T> v;
v.reserve(2);
T & a = v.emplace_back(a, b, c);
T & b = v.emplace_back(x, y, z);
Run Code Online (Sandbox Code Playgroud)

如果new 小于或等于当前值,则末尾的插入不会失效.sizecapacity