C++의 이동 구조 함수 및 move 문장 예시 상세 설명

머리말
본 고 는 주로 C++에서 모 바 일 구조 함수 와 move 문장 에 관 한 내용 을 소개 하고 참고 학습 을 제공 합 니 다.다음은 더 이상 말 하지 않 겠 습 니 다.상세 한 소 개 를 해 보 겠 습 니 다.
먼저 작은 예 를 보 자.

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>

using namespace std;

int main()
{
 string st = "I love xing";
 vector<string> vc ;
 vc.push_back(move(st));
 cout<<vc[0]<<endl;
 if(!st.empty())
 cout<<st<<endl;

 return 0;
}
결 과 는:
 

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>

using namespace std;

int main()
{
 string st = "I love xing";
 vector<string> vc ;
 vc.push_back(st);
 cout<<vc[0]<<endl;
 if(!st.empty())
 cout<<st<<endl;

 return 0;
}
결 과 는:
 
이 두 애플 릿 의 유일한 차이 점 은 vc.push 를 호출 하 는 것 입 니 다.back()문자열 을 용기 에 삽입 할 때 첫 번 째 코드 는 move 문 구 를 사 용 했 고 두 번 째 코드 는 move 문 구 를 사용 하지 않 았 습 니 다.출력 결과 차이 도 뚜렷 합 니 다.첫 번 째 코드 에 서 는 원래 문자열 st 가 비어 있 고 두 번 째 코드 에 서 는 원래 문자열 st 의 내용 이 변 하지 않 았 습 니 다.
자,이 두 코드 의 출력 결과 간 의 차 이 를 기억 하 세 요.다음은 이동 구조 함 수 를 간단하게 소개 하 겠 습 니 다.
이동 구조 함 수 를 소개 하기 전에 우 리 는 먼저 복사 구조 함 수 를 되 돌아 보아 야 한다.
C++는 세 가지 상황 에서 복사 구조 함수(오류 가 있 을 수 있 음)를 호출 한 다 는 것 을 잘 알 고 있 습 니 다.첫 번 째 상황 은 함수 형 실제 결합 일 때 두 번 째 상황 은 함수 가 돌아 올 때 함수 스 택 의 대상 은 함수 의 반환 으로 복사 되 고 세 번 째 상황 은 한 대상 으로 다른 대상 을 초기 화 할 때 도 복사 구조 함 수 를 호출 합 니 다.
이 세 가지 상황 을 제외 하고 복사 구조 함 수 를 호출 합 니 다.또한 한 대상 을 다른 대상 에 게 할당 하면 이 때 다시 불 러 오 는 할당 연산 자 함 수 를 호출 합 니 다.
복사 구조 함수 든 다시 불 러 오 는 할당 연산 자 함수 든 저 는 그때 C+수업 을 할 때 선생님 께 서 지침 의 얕 은 층 복사 문 제 를 주의해 야 한다 고 거듭 강조 하 셨 던 것 으로 기억 합 니 다.
여기 서 복사 구조 함수 의 얕 은 층 복사 문 제 를 간단하게 회상 해 보 겠 습 니 다.
우선 얕 은 층 으로 복 제 된 코드 를 보 세 요.

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>

using namespace std;

class Str{
 public:
 char *value;
 Str(char s[])
 {
 cout<<"      ..."<<endl;
 int len = strlen(s);
 value = new char[len + 1];
 memset(value,0,len + 1);
 strcpy(value,s);
 }
 Str(Str &v)
 {
 cout<<"        ..."<<endl;
 this->value = v.value;
 }
 ~Str()
 {
 cout<<"      ..."<<endl;
 if(value != NULL)
  delete[] value;
 }
};

int main()
{

 char s[] = "I love BIT";
 Str *a = new Str(s);
 Str *b = new Str(*a);
 delete a;
 cout<<"b        :"<<b->value<<endl;
 delete b;
 return 0;
}
출력 결 과 는:
 
우선 결 과 는 예상 에 부합 되 지 않 습 니 다.b 대상 의 문자열 도 I love BIT 이 기 를 바 랍 니 다.그러나 출력 은 비어 있 습 니 다.이것 은 b->value 와 a->value 가 같은 메모리 영역 을 가리 키 기 때 문 입 니 다.delete a 일 때 이 메모리 영역 은 회수 되 었 기 때문에 b->value 로 그 메모리 에 접근 하 는 것 은 실제 적 으로 적합 하지 않 습 니 다.그리고 제 가 실행 할 때 프로그램 이 무 너 지지 않 았 지만,그러나 프로그램 이 붕 괴 될 위험 이 있 습 니 다.delete b 일 때 그 메모리 영역 은 다시 한 번 방출 되 었 고 두 번 같은 메모 리 를 방출 하 는 것 은 상당히 위험 하기 때 문 입 니 다.
우 리 는 vagrind 로 검 사 를 해 보 았 는데,상당히 많은 메모리 오류 가 있 음 을 발견 하 였 다.
 
그 중 하 나 는 Invalid free,즉 b 를 삭제 할 때 석조 함 수 를 호출 하여 이미 방출 된 공간 에 대해 다시 한 번 방출 한 것 이다.
그럼 심층 복 제 는 어떻게 써 야 하나 요?
코드 는 다음 과 같 습 니 다:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>

using namespace std;

class Str{
 public:
 char *value;
 Str(char s[])
 {
 cout<<"      ..."<<endl;
 int len = strlen(s);
 value = new char[len + 1];
 memset(value,0,len + 1);
 strcpy(value,s);
 }
 Str(Str &v)
 {
 cout<<"        ..."<<endl;
 int len = strlen(v.value);
 value = new char[len + 1];
 memset(value,0,len + 1);
 strcpy(value,v.value);
 }
 ~Str()
 {
 cout<<"      ..."<<endl;
 if(value != NULL)
 {
  delete[] value;
  value = NULL;
 }
 }
};

int main()
{

 char s[] = "I love BIT";
 Str *a = new Str(s);
 Str *b = new Str(*a);
 delete a;
 cout<<"b        :"<<b->value<<endl;
 delete b;
 return 0;
}
결 과 는:
 
이번에 우리 가 예상 한 효과 에 도 달 했 습 니 다.그리고 vagrind 로 검 측 해 보 니 메모리 오류 가 없 었 습 니 다!
 
따라서 복사 구조 함 수 를 쓸 때 지침 의 얕 은 층 복사 문 제 를 주의해 야 한 다 는 것 을 명심 하 세 요! 
자,복사 구조 함 수 를 돌 이 켜 보고 이동 구조 함수 로 돌아 갑 니 다.
가끔 우 리 는 이러한 상황 을 만 날 수 있 습 니 다.우 리 는 대상 a 로 대상 b 를 초기 화하 고 대상 a 를 사용 하지 않 습 니 다.그러나 대상 a 의 공간 은 아직 있 습 니 다.(구조 분석 전에)구조 함 수 를 복사 한 이상 사실은 a 대상 의 내용 을 b 에 복사 하 는 것 입 니 다.그러면 왜 우 리 는 a 의 공간 을 직접 사용 할 수 없 습 니까?이렇게 하면 새로운 공간의 분 배 를 피하 고 구조의 원 가 를 크게 낮 출 수 있다.이것 이 바로 이동 구조 함수 디자인 의 취지 이다.
아래 의 이 그림 은 복사 구조 함수 와 이동 구조 함수 의 차 이 를 잘 설명 한다.

알 아 봤 어?
통속 적 인 해석 은 복사 구조 함수 에서 지침 에 대해 우 리 는 반드시 심층 복 제 를 사용 해 야 하고 이동 구조 함수 에서 지침 에 대해 우 리 는 얕 은 층 복 제 를 사용 해 야 한 다 는 것 이다.
하지만 지침 의 얕 은 층 복 제 는 매우 위험 하 다 고 언급 했다.맞 아,정말 위험 해.그리고 위의 예 를 통 해 우 리 는 얕 은 층 의 복사 가 위험한 이 유 는 두 바늘 이 공동으로 메모리 공간 을 가리 키 기 때문이다.만약 에 첫 번 째 지침 이 이 를 방출 하면 다른 지침 의 방향 은 합 법 적 이지 않 기 때문이다.그래서 우 리 는 첫 번 째 지침 이 공간 을 방출 하 는 것 을 피하 면 된다.피 하 는 방법 은 첫 번 째 포인터(예 를 들 어 a->value)를 NULL 로 설정 하 는 것 입 니 다.이렇게 분석 함 수 를 호출 할 때 NULL 여 부 를 판단 하 는 문구 가 있 기 때문에 a->value 가 가리 키 는 공간(동시에 b->value 가 가리 키 는 공간)을 분석 할 때 회수 하지 않 습 니 다.
그래서 우 리 는 위의 복사 구조 함수 의 코드 를 수정 할 수 있다.

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>

using namespace std;

class Str{
 public:
 char *value;
 Str(char s[])
 {
 cout<<"      ..."<<endl;
 int len = strlen(s);
 value = new char[len + 1];
 memset(value,0,len + 1);
 strcpy(value,s);
 }
 Str(Str &v)
 {
 cout<<"        ..."<<endl;
 this->value = v.value;
 v.value = NULL;
 }
 ~Str()
 {
 cout<<"      ..."<<endl;
 if(value != NULL)
  delete[] value;
 }
};

int main()
{

 char s[] = "I love BIT";
 Str *a = new Str(s);
 Str *b = new Str(*a);
 delete a;
 cout<<"b        :"<<b->value<<endl;
 delete b;
 return 0;
}
결 과 는:
 
수 정 된 복사 구조 함 수 는 얕 은 층 의 복 제 를 사 용 했 지만 결 과 는 우리 가 원 하 는 효 과 를 얻 을 수 있 습 니 다.관건 은 복사 구조 함수 에서 마지막 으로 v.value 를 NULL 로 설정 하 는 것 입 니 다.그러면 a 를 분석 할 때 a->value 가 가리 키 는 메모리 공간 을 회수 하지 않 습 니 다.
이렇게 a 로 b 를 초기 화 하 는 과정 에서 실제로 우 리 는 메모리 개발 을 줄 이 고 구조 원 가 를 낮 추 었 다.
그러나 주의해 야 할 것 은 우리 가 이렇게 사용 하 는 전 제 는 a 로 b 를 초기 화 한 후에 a 우 리 는 필요 하지 않 습 니 다.가장 좋 은 것 은 초기 화 를 완성 한 후에 a 를 분석 하 는 것 입 니 다.만약 에 우리 가 a 로 b 를 초기 화 한 후에 도 a 를 조작 해 야 한다 면 이런 얕 은 층 으로 복사 하 는 방법 은 적합 하지 않다.
그래서 C++는 이동 구조 함 수 를 도입 하여 이런 것 을 전문 적 으로 처리 하고 a 로 b 를 초기 화한 후에 a 를 분석 하 는 상황 을 말한다.
*************************************************************
**이동 구조 함수 의 매개 변 수 는 복사 구조 함수 와 달리 복사 구조 함수 의 매개 변 수 는 왼쪽 값 참조 이지 만 이동 구조 함수 의 초기 값 은 오른쪽 값 참조 입 니 다.(오른쪽 값 인용 에 대하 여 여러분 은 제 이전의 글 을 보 거나 다른 자 료 를 찾 을 수 있 습 니 다).이 는 이동 구조 함수 의 매개 변 수 는 오른쪽 값 이나 망 값 을 참조 하 는 것 을 의미한다.즉,하나의 오른쪽 값 을 사용 하거나 망 값 을 다른 대상 으로 초기 화 할 때 만 이동 구조 함 수 를 호출 하 는 것 이다.그 move 문 구 는 왼쪽 값 을 망 값 으로 바 꾸 는 것 이다.
모 바 일 구조 함수 가 가장 많이 응용 되 는 곳 이 STL 중 입 니 다.
하나의 코드 를 드 리 겠 습 니 다.move 사용 과 move 적용 되 지 않 는 차이 점 을 스스로 검증 하 세 요.

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
using namespace std;

class Str{
 public:
 char *str;
 Str(char value[])
 {
  cout<<"      ..."<<endl;
  str = NULL;
  int len = strlen(value);
  str = (char *)malloc(len + 1);
  memset(str,0,len + 1);
  strcpy(str,value);
 }
 Str(const Str &s)
 {
  cout<<"      ..."<<endl;
  str = NULL;
  int len = strlen(s.str);
  str = (char *)malloc(len + 1);
  memset(str,0,len + 1);
  strcpy(str,s.str);
 }
 Str(Str &&s)
 {
  cout<<"      ..."<<endl;
  str = NULL;
  str = s.str;
  s.str = NULL;
 }
 ~Str()
 {
  cout<<"    "<<endl;
  if(str != NULL)
  {
  free(str);
  str = NULL;
  }
 }
};
int main()
{
 char value[] = "I love zx";
 Str s(value);
 vector<Str> vs;
 //vs.push_back(move(s));
 vs.push_back(s);
 cout<<vs[0].str<<endl;
 if(s.str != NULL)
 cout<<s.str<<endl;
 return 0;
}
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가 치 를 가지 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기