beet's soil

競プロのことなど

std::vector::emplaceのargsに自身の要素を指定してはいけない

突然ですが以下のコードは何が出力されるでしょうか?

#include<vector>
#include<iostream>
#include<numeric>
using namespace std;
signed main(){
  vector<int> v(8);
  iota(v.begin(),v.end(),0);
  v.pop_back();
  v.emplace(v.begin(),v.back());
  cout<<v.capacity()<<endl;
  for(int x:v) cout<<x<<" ";
  cout<<endl;
  return 0;
}

当然
6 0 1 2 3 4 5 6
になってほしくないですか?僕はなってくれると思ってました。
実際僕のローカル環境ではそうなりました。

これを踏まえた上でこれらのオンライン実行環境での動作を見てください。
Paiza: Online PHP/Java/C++... editor and compiler | paiza.IO
ideone: Ideone.com - YD77BF - Online C++0x Compiler & Debugging Tool
wandbox: [Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ
yukicoder: オンライン実行 - yukicoder


5 0 1 2 3 4 5 6

は?キレそう
wandboxのバージョン機能で試したところ、gccの6.3までのバグっぽい。
未定義動作でした。(2018/03/14追記) eiyaさんありがとうございます。


AtCoder( GCC 5.4.1 ) とか CSA (バージョン書いてないけどバグった)とかでは気をつけましょう。
CodeForcesとyukicoderはgcc7.2に対応しているのでデフォルト設定を変えておいた方がいいかもしれません。


そこまで厳密に調べたわけではないんですが、要素数をいじるような操作(resize()とかpop_back()とかpush_back()とか)を行なった後は、emplaceのargsに自身の要素を指定してはいけないようです。
対策はそこまで面倒ではなくて、vector::emplace ではなく vector::insert を使えばいいだけです。

別に仕様とかではないっぽい(実際gcc7系以降では修正されている)
vector::emplace - cpprefjp C++日本語リファレンス

gcc7で修正されている例
wandbox: [Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ
yukicoder: オンライン実行 - yukicoder

全部未定義という仕様でした(うーん)
そもそももっと大きな括りとして変更操作時には再確保が行われる可能性があるので、引数に自身の参照を与えると全て未定義になるようです。
回避策としては一度変数に退避するか、コンストラクタで一時オブジェクトを作るかでしょうか(うーん)



B - Holes

上の問題を解いていて軽い気持ちで番兵入れようと思って

    g.emplace(g.begin(),g[m-1]);
    g.push_back(g[1]);

したらバグって1時間解けたのでいろいろ試したところコンパイラバグ未定義動作だとわかってつらかった。
C++はクソ
それではみなさん、快適なC++ライフを!w