在一个循环中对2个向量进行操作的问题

时间:2014-04-08 20:11:28

标签: c++ vector sfml

当我使用这个循环时,代码不能正常工作:

for(int i = 0; i < INTRO_LOGO_COUNT; i++)
{
    char path_buffer[32]; // 32 = logo_xxx.png
    sprintf(path_buffer, "data/texture/intro/logo_%d.png", i);
    std::cout << path_buffer;

    m_vecTextures.push_back(sf::Texture());
    m_vecTextures.back().loadFromFile(path_buffer);

    m_vecSprites.push_back(sf::Sprite());
    m_vecSprites.back().setTexture(m_vecTextures[i]);

    // Center
    m_vecSprites.back().setPosition(
        SCREEN_WIDTH / 2 - m_vecSprites.back().getLocalBounds().width / 2,
        SCREEN_HEIGHT / 2 - m_vecSprites.back().getLocalBounds().height / 2);
    m_vecSprites.back().setColor(sf::Color(255, 255, 255, 0)); // Opacity : 100%
}

纹理混合,只有第二个纹理才有效。 (INTRO_LOGO_COUNT定义为2) 并且第一纹理具有有效尺寸但是来自第二纹理的图像。 第二个纹理具有有效的大小和图像。 但经过1次更改(溢出为2次循环):

for( int i = 0; i < INTRO_LOGO_COUNT; i++ )
{
    char path_buffer[32]; // 32 = logo_xxx.png
    sprintf(path_buffer, "data/texture/intro/logo_%d.png", i);
    std::cout << path_buffer;

    m_vecTextures.push_back(sf::Texture());
    m_vecTextures.back().loadFromFile(path_buffer);
}

for( int i = 0; i < INTRO_LOGO_COUNT; i++ )
{
    m_vecSprites.push_back(sf::Sprite());
    m_vecSprites.back().setTexture(m_vecTextures[i]);
    // Center
    m_vecSprites.back().setPosition(
        SCREEN_WIDTH / 2 - m_vecSprites.back().getLocalBounds().width / 2,
        SCREEN_HEIGHT / 2 - m_vecSprites.back().getLocalBounds().height / 2);
    m_vecSprites.back().setColor(sf::Color(255, 255, 255, 0)); // Opacity : 100%
}

一切正常。 哪里有问题?我尝试了不同的方法,但总是有相同的效果。 谢谢!

2 个答案:

答案 0 :(得分:1)

根据API提取的信息进行更新

首先,您不应该使用sprintfsprintf非常不安全,如果你不小心,你可以很容易地缓冲溢出。如果您要坚持使用C函数,至少使用snprintf。其次,你不是自己清理字符串,也不是在任何地方放置NULL终止符。这很容易导致未定义的行为。

您使用的是C ++,因此请使用stringstream并省去自己的努力

我会写这个,虽然我个人会使用移动语义,或复制构造函数,而不是继续编辑“返回”对象......但那只是我

其次,它被保存为参考并且你没有使用指针的事实意味着我们的指针不能改变......所以Vector不能被使用,除非你可以保证它不会在以后调整大小。 ...如果你想使用矢量小心

m_vectTextures.reserve(INTRO_LOGO_COUNT); //reserves size so resize won't occur
for( int i = 0; i < INTRO_LOGO_COUNT; i++)
{
    sf::Color color(255, 255, 255, 0); // Opacity : 100%

    const char* prefix = "data/texture/intro/logo_";
    const char* suffix = ".png";
    std::stringstream ostr;
    ostr << prefix << i << suffix;
    std::string path( ostr.str() )
    std::cout << path;

    // if the above doesnt cut it, consider the same idea but using snprintf to read the 3 characters you need instead of an entire buffer

    m_vecTextures.push_back( sf::Texture() );
    sf::Texture& texture = m_vecTextures.back();
    texture.loadFromFile( path.c_str() ); //if you need a string

    m_vecSprites.push_back( sf::Sprite() );
    sf::Sprite& sprite = m_vecSprites.back();
    sprite.setTexture(texture);

    // Center
    sprite.setPosition(
        ( SCREEN_WIDTH - sprite.getLocalBounds().width ) / 2,
        ( SCREEN_HEIGHT - sprite.getLocalBounds().height ) / 2 );
    sprite.setColor( color );

    //since you still aren't sure and I don't know a better way to check
    std::cout << "sprite " << i << " is using texture of " << i
              << " which had a name of " << path << std::endl;
    //if you have a getter to check any of this now would be a good time.
}

替代

  1. 使用指针向量
  2. 使用listdequeue代替vector

答案 1 :(得分:1)

原因是从vector的实现。创建向量时,它会分配内存的修复大小,例如,向量的初始化大小为A.当您将元素推入向量并且大小达到A时,向量将自动重新分配其他连续大小为2 * A的内存块,如果无法在同一地址重新分配大小为2 * A的内存块,它将分配一个新的内存块并将旧内存中的内容复制到新内存块。 / p>

所以在你的第一个循环中:

m_vecSprites.back().setTexture(m_vecTextures[i]);

从您提供的链接,函数“setTexture”的定义是:

void Sprite::setTexture(const Texture& texture, bool resetRect)
{
    // Recompute the texture area if requested, or if there was no valid texture & rect before
    if (resetRect || (!m_texture && (m_textureRect == sf::IntRect())))
        setTextureRect(IntRect(0, 0, texture.getSize().x, texture.getSize().y));

    // Assign the new texture
    m_texture = &texture;
}

成员变量'm_texture'是指针类型

功能'setTexture'获取对m_vecTextures [i]的引用,但由于矢量'm_vecTextures'仍会增加,如果它达到初始大小,矢量将调整大小并移动内存块,参考可能会变为有效的。

如果向量初始化大小为INTRO_LOGO_COUNT,则第一个循环将正常工作。