web-dev-qa-db-ja.com

コンパイルエラーを与えるconstオブジェクトのベクトル

私はコードで以下を宣言しました

vector <const A> mylist; 

次のコンパイルエラーが発生します-

new_allocator.h:75: error: `const _Tp* __gnu_cxx::new_allocator<_Tp>::address(const _Tp&) const \[with _Tp = const A]' and `_Tp* __gnu_cxx::new_allocator<_Tp>::address(_Tp&) const [with _Tp = const A]' cannot be overloaded

しかし、宣言した場合-

vector <A> mylist;

私のコードはコンパイルされます。

このコンテキストではconstは許可されていませんか?

みんなの参考のためにここに私のコードをコピーしています-

#include <iostream>
#include <vector>

using namespace std;
class A
{
public:
    A () {cout << "default constructor\n";}
    A (int i): m(i) {cout << "non-default constructor\n";}

private:
    int m;
};

int main (void)
{
    vector<const A> mylist;

    mylist.Push_back(1);

    return 0;
}
37
Satabdi

ベクター内のアイテムは割り当て可能でなければなりません(または、標準のより新しいバージョンでは、移動可能)。 constオブジェクトは割り当て可能ではないため、それらをベクトルに格納しようとすると失敗します(または少なくともcan fail-コードは無効ですが、コンパイラは自由にそれを受け入れることができます)とにかく、それが選択した場合、ほとんどのプログラマーは一般的に無効なコードを拒否することを好みますが)。

本当に知識が豊富であると思いますが、ひどくやりたい場合は、constであっても割り当て可能な型を次のように定義できます。

class ugly { 
    mutable int x;
public:
    ugly const &operator=(ugly const &u) const { 
        x = u.x;
        return *this;
    }
};

私はあなたがそうだと信じていますすべきvectorであっても、このタイプのアイテムをconstに保存できます。これらのベクトルを作成する簡単なテストは、VC++で成功します。これは一部の古いコンパイラでは失敗しましたが(たとえば、g ++ 4.8.1で失敗しました)、かなり最近のコンパイラ(VC++は少なくとも2015年に戻って、g ++は少なくとも5.4に戻って、clang ++は少なくとも4.0に戻っています)で動作します。それをサポートするそれぞれの最初のバージョンを追跡しようとしました。

現在のコンパイラーでは、constオブジェクトの移動をサポートするタイプがおそらく同様に機能します。しかし、それが明白ではなかった場合に備えて、constとマークされていても、これによりオブジェクトを変更できます。これは明らかに、ユーザーの合理的な期待に対する直接の違反であるため、ほとんどの場合問題であり、解決策ではありません。

35
Jerry Coffin

Push_backメソッドの使用が問題です。 emplace_backがコンパイルされます。別の代替方法(ここで説明しない状況全体に依存します)は、挿入されたアイテムがベクトルの外側にある場合、vector<A const&>を使用することです。ベクトル内の項目は割り当て可能である必要はありませんが、割り当て可能でない場合、一部のメンバー関数とアルゴリズムを使用できません。

説明:

Push_backは、firstのデフォルトでベクトル内にAを構築し、then指定された参照を(copy-constructを使用して)割り当てます。これはconst資格を破るので、コンパイルされません。

emplace_backは「完全転送」を使用して、実際のコンストラクターを直接呼び出します。

11
lip