3

私が使用しているコードの簡略版は次のとおりです。

namespace BasketNovel {

void Engine::BuryEntities()
{
    std::list<Entity*>::iterator iter = p_entities.begin();
    while (iter != p_entities.end())
    {
        if ( (*iter)->getAlive() == false )
        {
            delete (*iter);
            iter = p_entities.erase( iter ); //.erase returns next element
        }
        else iter++;
    }
}
}

Intel Static Analysis から次の警告が表示されます。

BasketNovel.cpp(567): 警告 #12221: "std::_List_iterator > > std::list >::erase(std::_List_const_iterator > >)" の呼び出しで実引数 2 として渡されたオブジェクト "iter" のスライスが発生します暗黙の型変換による

これは基本的に、次の場所で暗黙的な型変換を引き起こしていると言っていると思います。

iter = p_entities.erase( iter );

(注: コードを次のように変更しても、同じ警告が表示されます: p_entities.erase( iter++ ); )

上記で「スライス」しているものをよく理解していません。これは正確には何を意味し、この警告を解決するにはどうすればよいですか? 警告メッセージを完全にオフにするよりも、コードを少し複雑にしたほうがよいでしょう。

4

3 に答える 3

1

オブジェクトスライシングとは

オブジェクトスライシングは、オブジェクトの一部のみをコピー/移動するという事実です。これは、一般に、ベース/派生カップルで発生します。

struct Base { int i; };

struct Derived: Base { int j; };

void slice() {
    Derived d = {};

    Base b(d); // b is a "sliced" version of `d`
}

そして不快感につながる可能性があります。

ただし、これは誤検知です...

簡単にできますか?

はい、確かに。

// Place to be deleted values at the end
auto const it = std::partition(p_entities.begin(), p_entities.end(),
                    [](Entity const* e) { return not e or not e->getAlive(); });

// Delete them
std::for_each(it, p_entities.end(), [](Entity const* e) { delete e; });

// Remove them
p_entities.erase(it, p_entities.end());
于 2012-11-29T08:27:48.603 に答える
1

std::list::erase()メソッドが を期待していて、std::list<Entity*>::const_iteratorを渡しているようですstd::list<Entity*>::iterator。これは、C++11 サポートを使用してコードをコンパイルしていることを意味している可能性があります。

解決策の 1 つは、削除を 2 段階で実行することです。まず、生きていないオブジェクトへのポインタstd::for_eachを削除して設定するために使用します。0

#include <algorithm>

void deleteDead(Entity* e) { 
  if (e->getAlive()) return; 
  delete e;
  e = 0;
}
std::for_each(p_entities.begin(), p_entities.end(), deleteDead);

次に、[erase-remove idiom]( erase-remove idiomを使用して、 0.

#include <algorithm>
p_entities.erase(std::remove(p_entities.begin(), p_entities.end(), 0), 
                 p_entities.end() );
于 2012-11-29T06:42:35.940 に答える
0

他の作業を約 1 か月行った後、問題の解決策は基本的に変更することにあることに気付きました。

std::list::iterator

std::list::const_iterator

.erase() が const_iterator を必要とし、反復子から暗黙的な変換を行ったため、スライスが発生していました。

将来の型変更の可能性をカバーするために、ヘッダーで std::list を typedef することをお勧めします。

ただし、オブジェクトのスライスに関する定義は、この回答自体よりもはるかに役立つと思うため、MatthieuM. の回答を維持しています。

于 2012-12-26T06:33:34.210 に答える