우선, 본질적인 이유는 초기 용량이 0이고, 첫 번째 연산은 1로 확장되고, 두 번째 연산은 2배로 늘어나기 때문입니다.
mac에서 clang 를 사용하고 있습니다. 호출하는 stl 구현은 libcxx여야 합니다. libcxx의 벡터 push_back 구현 소스 코드를 통해 확인할 수 있습니다.
소스코드는 여기에서 보실 수 있습니다https://github.com/llvm-mirro...
으아아아
__push_back_slow_path의 구현은 다음과 같습니다
으아아아
먼저 용량을 확장하고, __recommend는 확장 작업을 한 다음, __a 후반부에 새로운 콘텐츠가 구축되어 1위로 배치되는 것을 볼 수 있습니다. 이동하거나 복사할 수 있으며 최종적으로 _swap_out_circular_buffer 함수를 실행합니다. __swap_out_circular_buffer의 구현은 다음과 같습니다.
으아아아
반복자와 크기의 처리를 볼 필요가 없습니다. 핵심은 이전 벡터의 데이터를 새 벡터 메모리 영역으로 복사하거나 이동하는 역할을 담당하는 __alloc_traits::__construct_backward입니다. __construct_backward의 구현은 다음과 같습니다
으아아아
move_if_noexp를 보면 이동 작업을 수행하려면 noexc가 있어야 한다는 점을 알 수 있는데, 이 작업은 end부터 시작해서 start까지 iterator가 감소하므로 역순으로 진행됩니다.
그래서 첫 번째 push_back을 실행할 때 용량이 부족한지 확인하고 __push_back_slow_path 함수를 실행한 후 벡터를 1로 확장하고 이동 생성자를 실행하면 원래 벡터가 비어 있으므로 추가 처리가 필요하지 않습니다.
첫 번째 인쇄입니다 Move constructor is called. source: hello
두 번째로 push_back을 실행하면 용량이 부족한지 확인하고 __push_back_slow_path 함수를 실행하여 벡터를 2로 확장한 후 이동 생성자를 실행합니다.
두번째 판입니다Move constructor is called. source: world
그런 다음 __swap_out_circular_buffer을 실행하고 __alloc_traits::__construct_backward을 호출합니다. 이동 생성자는 noException이 아니므로 복사 생성자를 한 번 호출합니다.
이번이 세 번째 인쇄입니다 Copy constructor is called. source: hello
요소가 더 많으면 후속 복사 생성자의 실행 순서가 원래 벡터의 순서와 반대로 되는 것을 알 수 있습니다. 그 이유는 위에서도 언급한 것처럼 작업이 끝에서 시작되고 반복자가 계속해서 감소합니다. 시작하다.
이동 생성자는 noException이 아니기 때문입니다. 이동 생성자를 noException(true)으로 선언하면 벡터가 복사 생성자를 호출하지 않습니다.
벡터의 push_back에는 확장된 저장 공간이 필요할 수 있습니다. 이 프로세스에는 원래 저장 영역의 원본 데이터를 새로 적용된 저장 영역으로 복사하는 작업이 포함됩니다. 동시에 push_back은 요소를 추가하는 과정에서 작업에서 예외가 발생하는 경우 컨테이너가 push_back 이전 상태를 유지하는지 확인해야 합니다. 따라서 예외가 발생할 수 있는 이동 생성자를 호출할 수 없습니다. 의미상 이동 구성 작업을 중단하면(예외 발생) 데이터가 손상될 수 있기 때문입니다.
의미적으로 말하면 데이터 손상이 발생하지 않으므로 예외가 발생할 수 있는 복사 생성자를 호출합니다. 물론 복사 생성자에서도 작업을 수행할 수 있습니다.
위에서는 복사 생성자가 호출되는 이유에 대해 설명합니다.
우선, 본질적인 이유는 초기 용량이 0이고, 첫 번째 연산은 1로 확장되고, 두 번째 연산은 2배로 늘어나기 때문입니다.
mac에서 clang 를 사용하고 있습니다. 호출하는 stl 구현은 libcxx여야 합니다. libcxx의 벡터 push_back 구현 소스 코드를 통해 확인할 수 있습니다.
소스코드는 여기에서 보실 수 있습니다https://github.com/llvm-mirro...
으아아아__push_back_slow_path의 구현은 다음과 같습니다
으아아아먼저 용량을 확장하고, __recommend는 확장 작업을 한 다음, __a 후반부에 새로운 콘텐츠가 구축되어 1위로 배치되는 것을 볼 수 있습니다. 이동하거나 복사할 수 있으며 최종적으로 _swap_out_circular_buffer 함수를 실행합니다.
으아아아__swap_out_circular_buffer의 구현은 다음과 같습니다.
반복자와 크기의 처리를 볼 필요가 없습니다. 핵심은 이전 벡터의 데이터를 새 벡터 메모리 영역으로 복사하거나 이동하는 역할을 담당하는 __alloc_traits::__construct_backward입니다.
으아아아__construct_backward의 구현은 다음과 같습니다
move_if_noexp를 보면 이동 작업을 수행하려면 noexc가 있어야 한다는 점을 알 수 있는데, 이 작업은 end부터 시작해서 start까지 iterator가 감소하므로 역순으로 진행됩니다.
그래서 첫 번째 push_back을 실행할 때 용량이 부족한지 확인하고 __push_back_slow_path 함수를 실행한 후 벡터를 1로 확장하고 이동 생성자를 실행하면 원래 벡터가 비어 있으므로 추가 처리가 필요하지 않습니다.
첫 번째 인쇄입니다
Move constructor is called. source: hello
두 번째로 push_back을 실행하면 용량이 부족한지 확인하고 __push_back_slow_path 함수를 실행하여 벡터를 2로 확장한 후 이동 생성자를 실행합니다.
두번째 판입니다
Move constructor is called. source: world
그런 다음
__swap_out_circular_buffer
을 실행하고__alloc_traits::__construct_backward
을 호출합니다. 이동 생성자는 noException이 아니므로 복사 생성자를 한 번 호출합니다.이번이 세 번째 인쇄입니다
Copy constructor is called. source: hello
요소가 더 많으면 후속 복사 생성자의 실행 순서가 원래 벡터의 순서와 반대로 되는 것을 알 수 있습니다. 그 이유는 위에서도 언급한 것처럼 작업이 끝에서 시작되고 반복자가 계속해서 감소합니다. 시작하다.
이동 생성자는 noException이 아니기 때문입니다. 이동 생성자를 noException(true)으로 선언하면 벡터가 복사 생성자를 호출하지 않습니다.
벡터의 push_back에는 확장된 저장 공간이 필요할 수 있습니다. 이 프로세스에는 원래 저장 영역의 원본 데이터를 새로 적용된 저장 영역으로 복사하는 작업이 포함됩니다. 동시에 push_back은 요소를 추가하는 과정에서 작업에서 예외가 발생하는 경우 컨테이너가 push_back 이전 상태를 유지하는지 확인해야 합니다. 따라서 예외가 발생할 수 있는 이동 생성자를 호출할 수 없습니다. 의미상 이동 구성 작업을 중단하면(예외 발생) 데이터가 손상될 수 있기 때문입니다.
의미적으로 말하면 데이터 손상이 발생하지 않으므로 예외가 발생할 수 있는 복사 생성자를 호출합니다. 물론 복사 생성자에서도 작업을 수행할 수 있습니다.