2011-08-16 9 views
4

const int *int *constは非常に異なります。同様にconst std::auto_ptr<int>std::auto_ptr<const int>と同様です。しかし、const std::vector<int>std::vector<const int>との区別はありません(実際には2番目が許可されているかどうかはわかりません)。どうしてこれなの?なぜstd :: vectorは含まれているオブジェクトにconstnessを渡しますか?

時々私はベクトルへの参照を渡したい機能を持っています。この関数はベクトル自体を変更すべきではありません(例えば、no push_back())が、含まれている値のそれぞれを変更したいとします。同様に、ベクトル構造を変更するだけで、既存のコンテンツを変更することはできません(これは奇妙ですが)。この種のものは、(例えば)std::auto_ptrで可能ですが、std::vector::front()(例えば)は

const T &front() const; 
T &front(); 

だけではなく、

T &front() const; 

これを表現する方法はありませんように定義されているため。私が何をしたいの

例:

//create a (non-modifiable) auto_ptr containing a (modifiable) int 
const std::auto_ptr<int> a(new int(3)); 

//this works and makes sense - changing the value pointed to, not the pointer itself 
*a = 4; 
//this is an error, as it should be 
a.reset(); 


//create a (non-modifiable) vector containing a (modifiable) int 
const std::vector<int> v(1, 3); 

//this makes sense to me but doesn't work - trying to change the value in the vector, not the vector itself 
v.front() = 4; 
//this is an error, as it should be 
v.clear(); 
+1

私は誰もこれについて言及していませんが、ポインターのconstベクトルはポインターが指すオブジェクトを変更することを可能にし、必要に応じて回避策として使用できます。 –

答えて

7

constコンテナがある場合は、通常、それが含まれている要素の本質的な部分を誰かが変更することを望まない理由があります。あなたが望むならば、コンテナがこれらの要素を完全に "所有"していると "債券を固めます"。

これは、よりハンドオフの歴史的で、より低レベルの「コンテナ」実装(すなわち、生の配列)とは対照的です。あなたが言うとおり、int const*int * constの間には大きな違いがあります。しかし標準的なコンテナは単にconstを渡すことを選択します。

+0

私はそれが理にかなっていると思いますが、それだけで他の人がいない間、いくつかのコンテナが(この質問の目的のために、私は 'のstd :: auto_ptr'コンテナ考える)それを行うことを奇数として私を打ちます。疑いのあるときはintのようにするという一般的な考え方を破るように見える。 – Karu

+0

@ Karu: 'std :: auto_ptr'をコンテナにしたいと思ったら、それはあなたの選択です...しかし、それは1つではないという事実を変えません。 :) –

4

違いvector<int>が含まれているint型を所有してのに対し、intへのポインタは、彼らがを指していることをint型を所有していないということです。 A vector<int>は、intメンバを持つstructとして概念化できます。メンバの数はまさに可変であることがあります。

ベクトルに含まれる値は変更できますが、ベクトル自体は変更できない関数を作成する場合は、反復子の引数を受け入れるように関数を設計する必要があります。

例:

void setAllToOne(std::vector<int>::iterator begin, std::vector<int>::iterator end) 
{ 
    std::for_each(begin, end, [](int& elem) { elem = 1; }); 
} 

あなたは、ヘッダー内の所望の機能性を置くために余裕があれば、のように、一般的な行うことができます。これは、設計上の決定だ

template<typename OutputIterator> 
void setAllToOne(OutputIterator begin, OutputIterator end) 
{ 
    typedef typename iterator_traits<OutputIterator>::reference ref; 
    std::for_each(begin, end, [](ref elem) { elem = 1; }); 
} 
1

あなたが示唆するものと構文的に大きな問題は、std::vector<const T>std::vector<T>と同じタイプではありません。したがって、何らかの変換なしでvector<const T>を期待する関数にvector<T>を渡すことはできませんでした。単純なキャストではなく、新しいvector<const T>の作成。そしてその新しいものは単に古いものとデータを共有することができませんでした。古いものから新しいものにデータをコピーまたは移動する必要があります。

std::shared_ptrでこれを取り除くことができますが、それは共有ポインタであるためです。あなたは、同じポインタを参照する2つのオブジェクトを持つことができるので、shared_ptr<const T>からstd::shared_ptr<T>からの変換は、(参照カウントをぶつけ超えて)悪くはありません。 shared_vectorのようなものはありません。彼らだけコピーされない、から移動することができるので、

std::unique_ptrはあまりにも動作します。したがって、それらのうちの1つだけがポインタを持つことになります。

だから、何を求めていることは、単純にはできません。

+0

あなたは 'std :: vector 'を持つことはできません。要素の型はコピーコンストラクタブルで、かつ割り当て可能でなければなりません。歓声とhth。、 –

+0

@ Alf:私はstd :: vectorが現在どのように動作しているかを知っています。質問者は、なぜそれが別の方法で動作しないのかを質問していました.std :: vector が実際に機能する場所です。 –

+0

const specializationからnon-constを派生させることで可能です:http://ideone.com/BYOnl。最大の問題は、**標準の**コンテナでは必要ないバーチャルデストラクタがないことです(ただし、コンテナを設計する場合は問題ありません)。その他の問題はありますか? – visitor

1
  • あなたは正しいですが、const intのベクトルを持つことはできません。これは主に要素が割り当てられないためです(ベクトルに含まれる要素の型の要件)。
  • あなただけのベクトルの要素を変更しますが、ベクター自身に要素を追加していない機能が必要な場合、これはSTLがあなたのために何をするか、主であるが - 要素の順序が中に含まれているコンテナについてとらわれない機能を持っていますこの関数は単純にイテレータのペアを取り、そのシーケンスのためにそのシーケンスを行い、それらがベクトルに含まれているという事実を全く知らない。
  • 要素が何であるかを知らなくても容器の中に何かを挿入する方法について知ってもらうために、「イテレータを挿入」検索します。たとえば、back_inserterはコンテナを受け取り、それが気にするものは、そのコンテナに「push_back」というメンバ関数があることを知ることです。