왜 참조 벡터를 만들 수 없습니까?


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
amit

2
@amit 링크가 더 이상 유효하지 않습니다. 공식 문서는 여기
Martin

답변:


339

벡터와 같은 컨테이너의 구성 요소 유형은 지정 가능 해야합니다 . 참조는 할당 할 수 없습니다 (선언 될 때 한 번만 초기화 할 수 있으며 나중에 참조 할 수는 없습니다). 다른 비 할당 유형은 컨테이너 구성 요소로 vector<const int>허용되지 않습니다 ( 예 : 허용되지 않음).


1
내가 벡터로 구성된 벡터를 가질 수 없다고 말하는가? (내가 그렇게했다고 확신한다 ...)
James Curran

8
예, std :: vector <std :: vector <int>>가 정확하고 std :: vector를 지정할 수 있습니다.
Martin Cote

17
실제로 이것이 "실제적인"이유입니다. T *가 T에서 불가능하다는 오류는 U &이며 이는 T를 할당 할 수 있어야하는 위반 요구 사항의 부작용 일뿐입니다. 벡터가 타입 매개 변수를 정확하게 확인할 수 있다면 아마도 "위반 된 요구 사항 : T & 할당 할 수 없음"이라고 표시 될 것입니다.
Johannes Schaub-litb

2
boost.org/doc/libs/1_39_0/doc/html/Assignable.html 에서 지정 가능한 개념을 확인하면 스왑을 제외한 모든 작업이 참조에 유효합니다.
아 미트

7
이것은 더 이상 사실이 아닙니다. C ++ 11부터 요소에 대한 조작 독립적 인 요구 사항은 "삭제 가능"이어야하며 참조는 그렇지 않습니다. stackoverflow.com/questions/33144419/…를 참조하십시오 .
laike9m

119

std::reference_wrapper, 참조를 모방하지만 할당 가능하며 "재 장착"될 수있는를 찾을 수 있습니다.


4
get()이 래퍼에서 클래스 인스턴스의 메소드에 액세스하려고 할 때 먼저 호출 하는 방법이 있습니까? 예를 들어 reference_wrapper<MyClass> my_ref(...); my_ref.get().doStuff();매우 참조하지 않습니다.
timdiels

3
참조를 반환하여 Type 자체로 캐스트 할 수 있습니까?
WorldSEnder

3
그렇습니다. 그러나 어떤 변환이 필요한지를 나타내는 컨텍스트가 필요합니다. 회원 액세스는 그렇게하지 않으므로 필요합니다 .get(). 무엇 timdiels 싶은 것은 operator.; 이에 대한 최신 제안 / 토론을 살펴보십시오.
underscore_d

31

본질적으로 참조는 생성 된 시점에만 설정할 수 있습니다. 즉, 다음 두 줄은 매우 다른 효과를 갖습니다.

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 2016 년

2
std :: vector <T>의 요소 ype는 기본 구성 가능하지 않아도됩니다. struct A {A (int);를 작성할 수 있습니다. 개인 : A (); }; 벡터 A; v.resize (100)와 같이 기본 구성 가능 해야하는 메소드를 사용하지 않는 한 v.resize (100, A (1));)
Johannes Schaub-litb

이 경우 어떻게 이런 push_back ()을 작성 하시겠습니까? 건설이 아닌 할당을 계속 사용합니다.
James Curran

3
제임스 커런, 기본 건설은 없습니다. push_back은 배치 뉴스 A를 미리 할당 된 버퍼로 보냅니다. 여기 참조 : stackoverflow.com/questions/672352/...를 . 참고 것이 주장은 벡터 기본이 아닌-작도 유형을 처리 할 수있는 유일한 것입니다. 물론 T &를 처리 할 수 ​​있다고 주장하지는 않습니다 (물론 할 수는 없습니다).
Johannes Schaub-litb

29

Ion Todirel은 이미 YES를 사용하여 답변을 언급했습니다 std::reference_wrapper. C ++ 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이지만 유형 인 경우 참조하지 않고"라고 쓸 수 있도록하는 것입니다. 따라서 std::remove_reference<MyClass&>::type글쓰기와 동일합니다 MyClass.
alastair

2
전혀 가치가 없습니다-그냥 쓸 수 있습니다 for (MyClass obj3 : vec) std::cout << obj3.getval() << "\n"; (또는 const for (const MyClass& obj3: vec)를 선언 getval()하면).
Toby Speight

14

boost::ptr_vector<int> 작동합니다.

편집 : 사용에 제안했다 std::vector< boost::ref<int> >당신은 할 수 없기 때문에 작업은 기본-구성하지 않습니다 boost::ref.


8
그러나 벡터 또는 기본이 아닌 구성 가능한 유형을 가질 수 있습니다. 기본 ctor를 사용하지 않도록주의해야합니다. 의 벡터
Manuel

1
@Manuel : 또는 resize.
궤도에서 가벼움 경주

5
Boost의 포인터 컨테이너는 포인트의 독점 소유권을 갖습니다. Quote : "공유 의미론이 필요할 때이 라이브러리는 필요한 것이 아닙니다."
Matthäus Brandl

12

C ++ 언어의 결함입니다. 참조 주소를 가져 오면 참조 된 오브젝트의 주소가 생성되므로 참조에 대한 포인터를 얻을 수 없으므로 참조 주소를 사용할 수 없습니다. std::vector요소에 대한 포인터와 함께 작동하므로 저장되는 값을 가리킬 수 있어야합니다. 대신 포인터를 사용해야합니다.


void * 버퍼를 사용하여 구현하고 새로 배치 할 수 있다고 생각합니다. 이것이 의미가있는 것은 아닙니다.
peterchen 2016 년

55
"언어의 결함"이 너무 강합니다. 의도적으로 설계된 것입니다. 벡터가 요소에 대한 포인터와 함께 작동해야한다고 생각하지 않습니다. 그러나 요소를 지정할 수 있어야합니다. 참고 문헌이 아닙니다.
Brian Neal

당신은 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유형의 객체를 포함 T, T수 있어야 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

다른 의견에서 알 수 있듯이 포인터 사용에 국한됩니다. 그러나 그것이 도움이된다면, 포인터와 직접 대면하지 않는 한 가지 기술이 있습니다.

다음과 같은 작업을 수행 할 수 있습니다.

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.