なぜ参照のベクトルを作成できないのですか?


351

私がこれをするとき:

std::vector<int> hello;

すべてがうまくいきます。ただし、代わりに参照のベクトルにすると、次のようになります。

std::vector<int &> hello;

次のような恐ろしいエラーが発生します

エラーC2528: 'ポインター':参照へのポインターが不正です

構造体への一連の参照をベクトルに入れたいので、ポインターをいじる必要はありません。なぜベクトルはこれについてかんしゃくを投げているのですか?代わりにポインタのベクトルを使用する唯一のオプションはありますか?


46
std :: vector <reference_wrapper <int>> helloを使用できます。参照informit.com/guides/content.aspx?g=cplusplus&seqNum=217
アミット

2
@amitリンクはもう有効ではありません。公式ドキュメントはこちら
Martin

回答:


339

ベクターなどのコンテナのコンポーネントタイプは割り当て可能でなければなりません。参照は割り当て可能ではありません(宣言時に初期化できるのは一度だけであり、後で他のものを参照させることはできません)。その他の割り当て不可のタイプもコンテナのコンポーネントとして許可されてvector<const int>いません。たとえば、許可されていません。


1
私はベクトルのベクトルを持つことができないと言っていますか?(私はそれをしたと確信しています...)
ジェームズ・カラン

8
はい、std :: vector <std :: vector <int>>は正しいです。std:: vectorが割り当て可能です。
Martin Cote、

17
実際、これが「実際の」理由です。T *がTに不可能であるというエラーはU&です。これは、Tが割り当て可能でなければならないという違反した要件の副作用です。:ベクトルは正確に型パラメータをチェックすることができたなら、それはおそらく、「T&割り当てられない違反要件」と言うでしょう
litb -ヨハネス・シャウブ

2
boost.org/doc/libs/1_39_0/doc/html/Assignable.htmlで割り当て可能なコンセプトを確認すると、スワップ以外のすべての操作が参照で有効です。
アミット

7
これはもはや真実ではありません。C ++ 11以降、要素の操作に依存しない要件は「消去可能」にすることだけであり、参照はそうではありません。stackoverflow.com/questions/33144419/…を参照してください。
laike9m 2018

119

はい、できます。std::reference_wrapper参照を模倣していますが、割り当て可能であり、「再装着」することもできます。


4
get()このラッパーでクラスのインスタンスのメソッドにアクセスしようとするときに最初に呼び出しを回避する方法はありますか?たとえばreference_wrapper<MyClass> my_ref(...); my_ref.get().doStuff();、あまり参考になりません。
timdiels 2014年

3
参照を返すことで、Type自体に暗黙的にキャストできませんか?
WorldSEnder 2014年

3
はい。ただし、これには、どの変換が必要かを示すコンテキストが必要です。メンバーアクセスではこれが行われないため、が必要です.get()。何timdiels望んでいることですoperator.。それに関する最新の提案/議論を見てください。
underscore_d

31

その性質上、参照は作成時にのみ設定できます。つまり、次の2行の効果は大きく異なります。

int & A = B;   // makes A an alias for B
A = C;         // assigns value of C to B.

さらに、これは違法です:

int & D;       // must be set to a int variable.

ただし、ベクトルを作成する場合、作成時にその項目に値を割り当てる方法はありません。基本的には、最後の例の全体を作成しているだけです。


10
「ベクトルを作成するとき、作成時にその項目に値を割り当てる方法はありません」このステートメントの意味がわかりません。「作成時のアイテム」とは何ですか?空のベクターを作成できます。また、.push_back()を使用して項目を追加できます。参照はデフォルトで構築できないことを指摘しているだけです。しかし、私は間違いなく、デフォルトで構築できないクラスのベクトルを持つことができます。
newacct 2009年

2
std :: vector <T>の要素ypeは、デフォルトで構築可能である必要はありません。struct A {A(int);と書くことができます。プライベート:A(); }; ベクトル<A> a; うまくいく-デフォルトの構成可能である必要があるようなメソッドを使用しない限り(v.resize(100);など)-代わりにv.resize(100、A(1));を実行する必要があります)
ヨハネスシャウブ-litb 2009年

そして、この場合、そのようなpush_back()をどのように記述しますか?構築ではなく割り当てを使用します。
James Curran、

3
James Curran、デフォルトの構築はそこで行われません。push_backだけの配置-ニュースAを事前に割り当てられたバッファーに入れます。こちらをご覧ください:stackoverflow.com/questions/672352/…私の主張は、ベクターがデフォルト以外の構成可能な型を処理できるということだけであることに注意しください。もちろん、T&を処理できるとは主張していません(もちろんできません)。
ヨハネスシャウブ-litb 2009年

29

Ion TodirelはすでにYESを使用して回答を述べましたstd::reference_wrapperC ++ 11以降、を使用してオブジェクトからオブジェクトを取得しstd::vector 、参照を削除するメカニズムがありますstd::remove_reference。以下は、オプションを使用g++clangてコンパイル
-std=c++11され、正常に実行された例です。

#include <iostream>
#include <vector>
#include<functional>

class MyClass {
public:
    void func() {
        std::cout << "I am func \n";
    }

    MyClass(int y) : x(y) {}

    int getval()
    {
        return x;
    }

private: 
        int x;
};

int main() {
    std::vector<std::reference_wrapper<MyClass>> vec;

    MyClass obj1(2);
    MyClass obj2(3);

    MyClass& obj_ref1 = std::ref(obj1);
    MyClass& obj_ref2 = obj2;

    vec.push_back(obj_ref1);
    vec.push_back(obj_ref2);

    for (auto obj3 : vec)
    {
        std::remove_reference<MyClass&>::type(obj3).func();      
        std::cout << std::remove_reference<MyClass&>::type(obj3).getval() << "\n";
    }             
}

12
std::remove_reference<>ここには価値がありません。のポイントは、std::remove_reference<>「タイプTですが、それが1の場合は参照ではない」と書けるようにすることです。だから、std::remove_reference<MyClass&>::typeちょうど書き込みと同じですMyClass
alastair 2016

2
その点ではまったく価値がありません-書くことができますfor (MyClass obj3 : vec) std::cout << obj3.getval() << "\n"; (またはconst for (const MyClass& obj3: vec)を宣言する場合は、必要に応じてgetval())。
Toby Speight 2017年

14

boost::ptr_vector<int> 働くでしょう。

編集:を使用するための提案でしたが、をstd::vector< boost::ref<int> >デフォルトで構築できないため機能しませんboost::ref


8
しかし、ベクトルまたはデフォルトで構築できないタイプを使用できますよね?デフォルトのctorを使用しないように注意する必要があるだけです。ベクターの
マヌエル

1
@Manuel:またはresize
2014

5
Boostのポインターコンテナーは、指示先の独占的な所有権を取得することに注意してください。引用:「共有セマンティクスが必要な場合、このライブラリは必要ありません。」
マテウスBrandlの

12

C ++言語の欠陥です。参照しようとするとオブジェクトのアドレスが参照され、参照へのポインタを取得できないため、参照のアドレスを取得することはできません。 std::vector要素へのポインタで動作するため、格納されている値を指すことができる必要があります。代わりにポインタを使用する必要があります。


void *バッファと配置newを使用して実装できると思います。これが意味をなさないということではありません。
peterchen 2009年

55
「言語の欠陥」が強すぎます。仕様によるものです。ベクトルが要素へのポインタで動作する必要はないと思います。ただし、要素は割り当て可能である必要があります。参照はありません。
ブライアンニール

sizeof参照も取得できません。
David Schwartz

1
参照へのポインタは必要ありません。参照があります。ポインタが必要な場合は、ポインタ自体を保持してください。ここで解決する問題はありません
Ion Todirel

10

TL; DR

std::reference_wrapperこのように使用してください:

#include <functional>
#include <string>
#include <vector>
#include <iostream>

int main()
{
    std::string hello = "Hello, ";
    std::string world = "everyone!";
    typedef std::vector<std::reference_wrapper<std::string>> vec_t;
    vec_t vec = {hello, world};
    vec[1].get() = "world!";
    std::cout << hello << world << std::endl;
    return 0;
}

Demo

長い答え

規格が示唆、標準コンテナのXタイプのオブジェクトを含むTTでなければならないErasableからX

Erasable 次の式の形式が正しいことを意味します。

allocator_traits<A>::destroy(m, p)

Aはコンテナのアロケータ型でmあり、アロケータインスタンスでpあり、型のポインタです*T。定義についてはこちらをご覧くださいErasable

デフォルトでstd::allocator<T>は、はベクターのアロケーターとして使用されます。デフォルトのアロケータでは、要件はの有効性と同じですp->~T()(これTは参照型でありp、参照へのポインタです)。ただし、参照へのポインタは不正であるため、式の形式が正しくありません。


3

他の人が述べたように、おそらくポインタのベクトルを代わりに使用することになるでしょう。

ただし、代わりにptr_vectorの使用を検討してください


4
ptr_vectorはストレージであるはずなので、この答えは機能しません。つまり、削除時にポインタが削除されます。だから彼の目的には使えない。
Klemens Morgenstern

0

他のコメントが示唆しているように、ポインタの使用に限定されています。しかし、それが役立つ場合は、ポインタに直接直面しないようにするための1つのテクニックを次に示します。

次のようなことができます:

vector<int*> iarray;
int default_item = 0; // for handling out-of-range exception

int& get_item_as_ref(unsigned int idx) {
   // handling out-of-range exception
   if(idx >= iarray.size()) 
      return default_item;
   return reinterpret_cast<int&>(*iarray[idx]);
}

reinterpret_cast必要ありません
Xeverous

1
他の答えが示すように、ポインターの使用に限定されません。
underscore_d
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.