返回引用时的std :: vector :: emplace_back错误(C ++ 17) [英] std::vector::emplace_back bug when returning references (C++17)

查看:60
本文介绍了返回引用时的std :: vector :: emplace_back错误(C ++ 17)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经尝试跟踪一个错误10多个小时,而现在我开始认为该错误不能站在我这一边.但是,我有一种感觉,可能是我正在忘记或误解某些东西.

I've been trying to trace a bug for 10+ hours now, and by now I'm starting to think that the bug can't be on my side. However, I have a feeling it could be me who's just forgetting or misunderstanding something.

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

I have a class member of type std::vector called temp_materials, and inside the constructor (when temp_materials is still empty), this code runs:

    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;

如果在复制过程中没有任何问题,stonewall1的内容应等于stonewall2,container1到container2是否正确?

If nothing goes wrong during the copying, stonewall1's contents should be equal to stonewall2, as should container1 to container2, correct?

但是,我随后将它们全部插入一个简单的向量中,其内容将在以后呈现:

However, I then insert all of them into a simple vector which's contents will be rendered later on:

    // 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);

现在,我希望有2个容器"多维数据集彼此堆叠,并且有2个石墙"多维数据集彼此堆叠,但这就是我得到的结果:

Now, I'd expect there to be 2 "container" cubes stacked on each other, and 2 "stonewall" cubes stacked on each other, but this is the result I'm getting:

但是,如果我将 Material stonewall2 = stonewallbug; 这一行移至stonewallbug和containerbug的创建之间,我会得到预期的结果.

If I however move the line Material stonewall2 = stonewallbug; to between the creation of stonewallbug and containerbug, I get the result I expect.

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

Noticing this, I made a very, very simple C++ program:

#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;
}

运行此命令的结果是很多无用的字符.但是,如果我在放置ref2之前输出了ref1,则它会输出预期的结果.在此处上,它表示矢量的emplace_back应该返回对以下内容的引用插入的元素,但对我来说似乎并不像它应该的那样工作.

And the result when running this is a lot of nonsense characters. However, if I output ref1 before ref2 is emplaced, it outputs the expected results. On here it says that vector's emplace_back is supposed to return a reference to the inserted element, but to me it doesn't seem like it's working like it should.

我误解了吗,或者这仅仅是g ++ 7.1中的非常明显的错误?

Am I misunderstanding something, or is this just a very obvious bug in g++ 7.1?

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

I can't believe I spent so many hours on such an obvious thing... :)

推荐答案

您必须谨慎使用容器元素的引用和迭代器.各种变异容器操作 invalidate 引用和迭代器.详细信息因容器和操作而异,但是对于 std :: vector ,所有插入操作(例如 push_back emplace_back )以及从末尾删除所有内容,通常会使引用和迭代器均无效(但请参见下文,避免这种情况的发生).

You have to be careful with references and iterators to container elements. Various mutating container operations invalidate references and iterators. The details vary by container and operation, but for std::vector, all inserting operations (such as push_back and emplace_back), as well as erasure from anything other than the end, invalidate both references and iterators in general (but see below for ways to avoid this).

因此,在下面的代码中,

Therefore, in the following code,

std::vector<T> v;

T & a = v.emplace_back(a, b, c);
T & b = v.emplace_back(x, y, z);

第二次调用 emplace_back 使引用 a 无效.(并且通过无效的引用访问对象具有不确定的行为.)

the second call of emplace_back invalidates the reference a. (And accessing an object through an invalid reference has undefined behaviour.)

为避免在 std :: vector 中失效,请使用 reserve capability 工具:

To avoid invalidation in a std::vector, use the reserve and capacity facilities:

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

如果新的 size 小于或等于当前的 capability ,则在末尾插入不会使 无效.

An insertion at the end does not invalidate if the new size is less than or equal to the current capacity.

这篇关于返回引用时的std :: vector :: emplace_back错误(C ++ 17)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆