your programing

벡터가 커질 때 이동 의미론을 적용하는 방법은 무엇입니까?

lovepro 2020. 10. 5. 20:32
반응형

벡터가 커질 때 이동 의미론을 적용하는 방법은 무엇입니까?


나는이 std::vector특정 클래스의 객체를 A. 클래스는 사소하지 않으며 복사 생성자 이동 생성자가 정의되어 있습니다.

std::vector<A>  myvec;

벡터를 A객체로 채우면 (예 :) 벡터의 요소의 새 복사본을 인스턴스화하기 myvec.push_back(a)위해 복사 생성자 A( const A&)사용하여 벡터의 크기가 커집니다 .

클래스의 이동 생성자가 A대신 사용 되도록 어떻게 든 강제 할 수 있습니까 ?


std::vector를 사용하여 이동 생성자와 소멸자가 throw하지 않는다는 것을 C ++ (특히 ) 에 알려야 합니다 noexcept. 그런 다음 벡터가 커지면 이동 생성자가 호출됩니다.

다음은 std::vector다음에 의해 존중되는 이동 생성자를 선언하고 구현하는 방법입니다 .

A(A && rhs) noexcept { 
  std::cout << "i am the move constr" <<std::endl;
  ... some code doing the move ...  
  m_value=std::move(rhs.m_value) ; // etc...
}

생성자가 아닌 경우 noexcept, std::vector다음 표준이 요구하는 예외 보증을 보장 할 수 없기 때문에, 그것을 사용할 수 없습니다.

표준에서 말하는 내용에 대한 자세한 내용은 C ++ Move 의미론 및 예외를 읽어보세요.

예외와 관련이있을 수 있다고 암시 한 Bo에게 감사합니다. 또한 Kerrek SB의 조언을 고려하고 emplace_back가능하면 사용 하십시오. 그것은 수 있습니다 빠른 (하지만 종종 아니다), 그것은 명확하고 컴팩트 수 있습니다,하지만 (특히 비 명시 적으로 생성자와) 몇 가지 함정도 있습니다.

편집 , 종종 기본값은 원하는 것입니다. 이동할 수있는 모든 항목을 이동하고 나머지는 복사합니다. 명시 적으로 요청하려면 다음을 작성하십시오.

A(A && rhs) = default;

그렇게하면 가능한 경우 noexcept가 발생합니다. 기본 Move 생성자가 noexcept로 정의되어 있습니까?

이전 버전의 Visual Studio 2015 및 이전 버전에서는 이동 의미 체계를 지원하더라도이를 지원하지 않았습니다.


흥미롭게도 gcc 4.7.2의 벡터는 이동 생성자와 소멸자가 모두 인 경우에만 이동 생성자를 사용합니다 noexcept. 간단한 예 :

struct foo {
    foo() {}
    foo( const foo & ) noexcept { std::cout << "copy\n"; }
    foo( foo && ) noexcept { std::cout << "move\n"; }
    ~foo() noexcept {}
};

int main() {
    std::vector< foo > v;
    for ( int i = 0; i < 3; ++i ) v.emplace_back();
}

이것은 예상 된 결과를 출력합니다.

move
move
move

내가 제거 할 때, noexcept에서 ~foo(), 결과는 다릅니다 :

copy
copy
copy

이것도이 질문에 대한 답이라고 생각합니다 .


std::vector재 할당시 이동 의미론을 사용 하도록 강제하는 유일한 방법 (C ++ 17 및 초기) 은 복사 생성자를 삭제하는 것 같습니다. :). 이런 식으로 컴파일 타임에 이동 생성자를 사용하거나 죽을 것입니다. :).

std::vector재 할당시 이동 생성자를 사용해서는 안되는 규칙이 많이 있지만 어디에서 사용해야하는지 에 대한 규칙 은 없습니다 .

template<class T>
class move_only : public T{
public:
   move_only(){}
   move_only(const move_only&) = delete;
   move_only(move_only&&) noexcept {};
   ~move_only() noexcept {};

   using T::T;   
};

라이브

or

template<class T>
struct move_only{
   T value;

   template<class Arg, class ...Args, typename = std::enable_if_t<
            !std::is_same_v<move_only<T>&&, Arg >
            && !std::is_same_v<const move_only<T>&, Arg >
    >>
   move_only(Arg&& arg, Args&&... args)
      :value(std::forward<Arg>(arg), std::forward<Args>(args)...)
   {}

   move_only(){}
   move_only(const move_only&) = delete;   
   move_only(move_only&& other) noexcept : value(std::move(other.value)) {};    
   ~move_only() noexcept {};   
};

Live code

Your T class must have noexcept move constructor/assigment operator and noexcept destructor. Otherwise you'll get compilation error.

std::vector<move_only<MyClass>> vec;

참고URL : https://stackoverflow.com/questions/8001823/how-to-enforce-move-semantics-when-a-vector-grows

반응형