std :: pair 내의 이니셜 라이저 목록


26

이 코드는 :

#include <iostream>
#include <string>

std::pair<std::initializer_list<std::string>, int> groups{ { "A", "B" }, 0 };

int main()
{
    for (const auto& i : groups.first)
    {
        std::cout << i << '\n';
    }
    return 0;
}

컴파일하지만 segfault를 반환합니다. 왜?

gcc 8.3.0 및 온라인 컴파일러에서 테스트되었습니다.


1
편의를 위해 : Godbolt은 링크 와 함께없이 std::pair .
맥스 랭 호프

답변:


24

std::initializer_list저장하기위한 것이 아니라 단지 초기화를위한 것입니다. 내부적으로는 첫 번째 요소와 크기에 대한 포인터를 저장합니다. 코드에서 std::string객체는 일시적이며 객체의 initializer_list소유권을 얻거나 수명을 연장하거나 복사하지 않으므로 (컨테이너가 아니기 때문에) 생성 후 즉시 범위를 벗어나지 만 initializer_list여전히 포인터를 갖습니다. 그래서 세분화 오류가 발생합니다.

보관하려면 std::vector또는 과 같은 용기를 사용해야합니다 std::array.


이것이 컴파일 가능하다는 것을 귀찮게합니다. 바보 같은 언어 :(
Orbit in Lightbit Races

1
@LightnessRaceswithMonica와 함께 쇠고기가 많이 initializer_list있습니다. 이동 전용 객체를 사용할 수 없으므로 예를 들어 unique_ptr 벡터로 list init을 사용할 수 없습니다. 의 크기는 initializer_list컴파일 타임 상수가 아닙니다. 그리고 사실 std::vector<int>(3)std::vector<int>{3}완전히 다른 일을합니다. 나를 슬프게 만들어 :(
bolov

그래 같은 ... :(
궤도에서 가벼움

3

조금만 더 자세히 설명하겠습니다. 기본 배열은 std::initializer_list임시와 비슷하게 동작합니다. 다음 수업을 고려하십시오.

struct X
{
   X(int i) { std::cerr << "ctor\n"; }
   ~X() { std::cerr << "dtor\n"; }
};

다음 코드에서의 사용법 :

std::pair<const X&, int> p(1, 2);
std::cerr << "barrier\n";

인쇄

ctor
dtor
barrier

첫 번째 줄 X부터 생성자의를 변환 하여 유형의 임시 인스턴스 가 만들어 1지고 파괴됩니다. 저장된 참조 p는 매달려 있습니다.

와 같이 std::initializer_list사용하면 :

{
   std::initializer_list<X> l { 1, 2 };
   std::cerr << "barrier\n";
}

그러면 기본 (임시) 배열이 l종료되는 한 존재합니다 . 따라서 출력은 다음과 같습니다.

ctor
ctor
barrier
dtor
dtor

그러나로 전환하면

std::pair<std::initializer_list<X>, int> l { {1}, 2 };
std::cerr << "barrier\n";

다시 출력

ctor
dtor
barrier

기본 (임시) 배열은 첫 번째 줄에만 존재하기 때문입니다. l그런 다음 요소에 대한 포인터를 역 참조하면 동작이 정의되지 않습니다.

라이브 데모가 여기 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.