복사생성자와 임시객체에 대해서

vani2의 이미지

1. 복사생성자를 다음과 같이 사용하면 단점이 있나요?

Example exp;
Example ex1 = Example(exp);

2. 객체를 함수의 매개변수로 전달할때 값에의한 전달과 참조에의한 전달의 차이가 무엇인가요?

void ab(Person a) {
...
}

void ab(Person& a) {
...
}

여러 소스들을 분석해보면 참조에 의한 전달이 더 효율적으로 보이는데도 불구하고 값에 의한 전달을 사용하는 함수가 많았는데요, 그렇게 하는 이유가 무엇인가요?

3. 복사생성자가 없는 객체를 함수의 인자로 사용할 경우 생성자가 1번 호출되고 파괴자가 2번 호출되던데 이유가 무엇인가요?

4. 임시객체의 소멸시기는 언제인가요?

경우1: 함수의 매개변수로 사용될때
경우2: 수식에 사용될때
경우3: 리턴값으로 사용될때

klara의 이미지

1. ex1 = exp와 비교해서라는 뜻이시죠? ex1 = exp는 복사 생성자를 한번 호출하는 구문이고 적으신 건 복사 생성자를 두번 호출하는 구문입니다.

2. 값은 복사하는 거고 참조는 포인터라고 생각하시면 됩니다. 효율은 객체의 크기가 크지 않다면 별차이가 없습니다. 비상수 참조로 넘기는건 포인터를 넘겼을 때의 문제점과 완전히 동일합니다. 비상수 참조이므로 함수안에서 함수밖에서 온 변수를 조작할 수 있고, 그에 대한 포인터나 참조를 구하는것도 가능합니다. 이게 필요하면 쓰는거고 필요없으면 안쓰는 건데 보통은 상수 참조를 가장 많이 씁니다.

3. 그런일은 없습니다. 정상적으로 종료된 생성자와 파괴자의 호출 횟수는 동일합니다.

4. 함수가 리턴되면(스택에서 내려가면) 소멸됩니다. 모든 구문은 함수입니다. 수식(예를 들어 덧셈 수식은 +연산자의 오버로딩으로 정의됩니다)도 함수입니다. 따라서 따로 구분할 필요가 없습니다. 리턴값의 경우에는 리턴할 때 한번 생성되고 리턴값의 복사 생성자에서 한번 생성된후에 복사 생성자가 리턴되면 함수안에서 생성된 객체가 소멸됩니다. 복사 생성자로 생성된 임시 객체는 함수밖에서 누가 받아주면 그때 또 함수 인자로 넘어가서 처리가 되는거고 아니면 그대로 소멸됩니다.

vani2의 이미지

그렇군요.

3번의 일이 왜 생긴건진 모르겠지만..

잘 이해 되었습니다. 감사합니다 :D

익명 사용자의 이미지

2번에서 차이는 객체가 아니라 기본 자료형으로 생각해보면 쉽습니다.
그냥 책에서 레퍼런스 설명하는 그래도 입니다.
레퍼런스면 값을 수정할 수 있습니다.
복사로 넘기면 값이 수정될 일은 없죠.

객체를 레퍼런스로 넘기는건 복사를 안한다는
성능상의 이유 또한 있는데
그럴 경우 값은 수정되면 안될때 const를 붙혀 줍니다.

3번은 짐작컨데 횟수를 생성자와 소멸자에서 출력문으로 확인했으리라 생각되는데
복사 생성자를 안만들면 없는게 아니고
컴파일러가 default로 복사 생성자를 만듭니다.
그래서 출력문을 통한 카운트로는 확인이 안된 것이라 추측되는군요
(복사 생성자는 작동했을겁니다.)

4번에서 임시객체가 리턴되는 경우에는 RVO라고 해서
컴파일러마다 다릅니다.

vani2의 이미지

3번의 경우 말씀하신대로 생성자와 소멸자에 출력문을 넣었는데요,

내부적으로 동적할당을 사용했는데 역시 이게 문제일까요..?

얕은 복사가 이루어진것 같군요.

shint의 이미지


책을 보거나. 네이버에서 검색해보면. 복사생성자에 대해서 알 수 있을거 같습니다.

아래 내용은 정확하지 않으니 대충 참고만 해보세요.

가능한한 직접 테스트를 해보세요.

1. 복사생성자를 다음과 같이 사용하면 단점이 있나요?

- 코드를 해석할때 보기 어렵습니다.
- 코드를 해석해야 알 수 있는 코드는 실무자들에 업무를 괴롭히는 나쁜 코드가 되기 쉽습니다.

2. 객체를 함수의 매개변수로 전달할때 값에의한 전달과 참조에의한 전달의 차이가 무엇인가요?

- 값은 100 바이트를 모두 복사하는거고. (판매)
- 참조는 4 바이트만 넘겨서 사용하는겁니다. (대여)

여러 소스들을 분석해보면 참조에 의한 전달이 더 효율적으로 보이는데도 불구하고 값에 의한 전달을 사용하는 함수가 많았는데요, 그렇게 하는 이유가 무엇인가요?

- 참조를 하게 되면. 어디서 값이 변경되었는지 알 수 없게 되는 경우가 있습니다.
- 값을 사용하게 되면. 값 자체의 보존이 되서 안전합니다. 그렇지만. 속도가 더 느린 문제점이 있습니다.

3. 복사생성자가 없는 객체를 함수의 인자로 사용할 경우 생성자가 1번 호출되고 파괴자가 2번 호출되던데 이유가 무엇인가요?

이 코드를 확인해 보는것이 좋을것 같습니다.

class CA
{
public:
	CA(){	printf("CA생성자 \n"); };
	~CA(){	printf("CA소멸자 \n"); };
	int a;
};
 
 
class Example
{
public:
	Example(){	printf("Example생성자1 \n"); };
	Example(int i);
	Example(const Example& copy);
	Example(const CA& copy);
	Example* fn_copy(const Example& copy);
	~Example(){	printf("Example소멸자 \n"); };
	int a;
};
 
Example::Example(int i) : a(i)
{
	printf("Example생성자2  : %d %d\n", i, a);
}
 
Example::Example(const Example& copy) : a(copy.a)
{
	printf("Example복사 생성자 : %d %d\n", copy.a, a);
}
 
Example::Example(const CA& copy) : a(copy.a)
{
	printf("Example CA복사 생성자 : %d %d\n", copy.a, a);
}
 
//error C2556: 'Example *Example::fn_copy(const Example &)' : 오버로드된 함수가 'int Example::fn_copy(const Example &)'과(와) 반환 형식만 다릅니다.
Example* Example::fn_copy(const Example& copy)
{
	a = copy.a;
	printf("Example복사 함수 : %d %d\n", copy.a, a);
	return (Example*)©
}
 
 
 
 
int main(int argc, char* argv[])
{
	Example exp;
 
	//이 방법은 알아보기 어렵다.
	exp.a = 12;
	Example ex1 = Example(exp);
 
	//이 방법이 알아보기 쉽다.
	ex1.a = 15;
	ex1 = *exp.fn_copy(ex1);
 
	printf("main : %d %d\n", ex1.a, exp.a);
 
	exp.a = 12;
	CA aa;
	aa.a = 20;
	Example ex2 = Example(aa);
 
	//복사 생성자'라는건
	//클래스 생성자에 함수인자값을 넣고. 초기화 한거 정도로 보인다.
	//말 자체는 맞지만. 복잡하다. ㅡ_ㅡ... 가능한한 풀어서 코딩해야 한다.
 
	return 0;
}
 
 
//출력 결과
//Example생성자1
//Example복사 생성자 : 12 12
//Example복사 함수 : 15 15
//main : 15 15
//CA생성자
//Example CA복사 생성자 : 20 20
//Example소멸자
//CA소멸자
//Example소멸자
//Example소멸자

4. 임시객체의 소멸시기는 언제인가요?

경우1: 함수의 매개변수로 사용될때
경우2: 수식에 사용될때
경우3: 리턴값으로 사용될때

코드로 테스트해보시는것이 좋을거 같습니다.

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

vani2의 이미지

친절한 설명 감사드립니다.

그런데


//error C2556: 'Example *Example::fn_copy(const Example &)' : 오버로드된 함수가 'int Example::fn_copy(const Example &)'과(와) 반환 형식만 다릅니다.
Example* Example::fn_copy(const Example& copy)
{
a = copy.a;
printf("Example복사 함수 : %d %d\n", copy.a, a);
return (Example*)©
}

이 부분이 이해가 잘 되지않네요...

fn_copy 라는 함수가 1개인것 같은데 어떻게 오버로드 된 것인가요?

shint의 이미지

ㅇ_ㅇ;; 리턴값이랑 참조가 같으면 그런 경우가 있던거 같습니다.
저도 잘은 모르겠습니다.

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.