c++ 에서 생성자의 초기화 리스트의 장점?

ssehoony의 이미지

초기화 리시트라고 하는게 맞는 용어인지는 모르겠군요.
제가 의도한 바는 클래스 생성자 뒤에 멤버변수 값을 초기화 하는 리스트를 넣는 문법을 의미하는 건데요.

레퍼런스나 const 변수에 대한 값을 설정하기 위해서는 그렇게 할 수 밖에 없는 것은 알겠는데요.
그 외의 변수는 그렇게 할 필요가 있나요?
그런 변수도 모조리 그렇게 초기화 하는 경우는 많이 보곤 합니다.
그게 뭔가 장점이 있어서 그런것이 아닐까 하는 궁금이 생겨서 이렇게 질문 드립니다.
그냥 단순이 코딩 스타일인가요?
제가 보긴엔 가독성이 떨어지는 듯 한데......

익명 사용자의 이미지

http://zho.pe.kr/view.html?file_name=doc/cpp.txt

Quote:
--------------------
생성자 구현시 유의사항
--------------------
Person::Person (const char * name, const float height)
{
_name = name;
_height = height;
}

보다는

Person::Person (const char * name, const float height)
: _name(name), _height(height)
{
}

를 사용하라. 위의 코드의 경우 _name과 _height 라는 멤버변수가 클래스 생성시에
한번 초기화되고 생성자에 의해 두번 초기화되지만, 아래 코드의 경우는 클래스가
생성되면서 한번만 초기화되기 때문에 더 효과적이다.

이때 _name() 과 _height() 등이 호출되는 순서는 클래스 내부에 멤버변수가 선언
된 순서이지 생성자에 나열된 순서가 아니라는 점을 유념해야 한다. 즉,

class Person {
public:
float _weight;
float _height;
Person(const float height);
};

Person::Person (const float height)
: _height(height), _weight(_height-100)
{
}

Person(10);

위와 같은 코드는 원치않는 결과를 유발하는데, 이유는 _weight 가 _height 보다
먼저 선언되었기 때문에 _height() 가 먼저 위치한 것과는 상관없이
_weight(_height-100) 가 먼저 호출되기 때문이다. 이때 _height 는 아직 생성되지
않은 상태이기 때문에 _weight 에는 10-100 이 아닌 다른 값이 들어가게 된다.
생성자에 열거된 순서로 멤버변수가 생성되지 않는 이유는 소멸자에서도 같은 순서
로 멤버변수가 소멸될 것이라는 보장을 할 수 없기 때문이다. 소멸자가 정의되어
있는 파일과 생성자가 정의되어 있는 파일이 동일한 파일이라는 보장은 없다. 그러
므로 소멸자도 생성자와 마찬가지로 클래스에 선언된 순서대로 멤버변수를 소멸시
키게 된다.

[REF] The ABCs of Writing C++ Classes :
http://www.acm.org/crossroads/xrds1-4/ovp.html

이것 말씀이신가요?

pok의 이미지

글의 요지가, "생성자를 최대한 작게 만드는 대신 초기화리스트를 이용해라" 인것 같네요.

Quote:
위의 코드의 경우 _name과 _height 라는 멤버변수가 클래스 생성시에 한번 초기화되고 생성자에 의해 두번 초기화되지만, 아래 코드의 경우는 클래스가 생성되면서 한번만 초기화되기 때문에 더 효과적이다.

이건 무슨말인가요?
인스턴스 생성시 할당되고 생성자로 대입연산을 통해 대입하는거랑
인스턴스 생성시 할당되고 초기화리스트로 대입하는거랑.. 똑같은것 아닌가요?

저도 질문자처럼 초기화리스트보다는 생성자로 초기화하는게 훨씬 나아보입니다.
초기화리스트는 포함객체초기화, 참조초기화, 상수초기화 이외에는 별로 사용해본적도 없고요.

dasomoli의 이미지

pok wrote:
인스턴스 생성시 할당되고 생성자로 대입연산을 통해 대입하는거랑
인스턴스 생성시 할당되고 초기화리스트로 대입하는거랑.. 똑같은것 아닌가요?

다른 것으로 알고 있습니다. More Effective C++ 이던가 Effective C++ 두권중 어딘가에서 본 거 같은데 아마 다음분께서 친절히 설명해주실 겁니다. 8)


dasomoli의 블로그(http://dasomoli.org)
dasomoli = DasomOLI = Dasom + DOLI = 다솜돌이
다솜 = 사랑하옴의 옛 고어.
Developer! ubuntu-ko! 다솜돌이 정석
uriel의 이미지

위에 손님이 쓰신 것을 다시 풀어서 써보겠습니다.

기본 타입들 (int나 long같은..)의 경우는 초기화 리스트를 사용하는 것이나, 생성자 안에서 대입을 하는 것이나 차이가 없습니다.

하지만 클래스 객체를 사용하는 경우는 조금 이야기가 달라집니다.

 Person::Person (Info name)
: _Info(name)
{
}

의 경우는 _Info라는 객체가 _Info(Info& info)의 생성자로 호출이 됩니다.
 Person::Person (Info name)
{
_Info = name;
}

의 경우는 _Info 객체가 _Info()의 기본 생성자로 초기화 된 후, 다시 대입 연산자(=)로 할당이 됩니다. 저도 이 내용이 MEC++던가, EC++던가 정확히 기억이 나지는 않네요.
doldori의 이미지

pok wrote:
인스턴스 생성시 할당되고 생성자로 대입연산을 통해 대입하는거랑
인스턴스 생성시 할당되고 초기화리스트로 대입하는거랑.. 똑같은것 아닌가요?

같지 않습니다. 생성과 대입의 차이에 대해서는 너무 얘기가 길어질 듯하니 생략하고,
위에서 인용된 글의 내용은 효율의 관점에서 대입보다 초기화 리스트를 쓰는 것이
낫다는 대표적인 이유입니다. 즉 대입을 사용한다면 디폴트 생성자, 대입 연산자의
2번의 함수 호출인 반면 초기화 리스트를 쓰면 해당 생성자 한 번의 호출로 초기화가
완료된다는 것입니다. 아마 대부분의 경우 그 차이는 그리 크지 않으리라 보지만
적어도 초기화 리스트가 대입보다 비효율적이지는 않다는 점은 확실합니다.

pok wrote:
저도 질문자처럼 초기화리스트보다는 생성자로 초기화하는게 훨씬 나아보입니다.
초기화리스트는 포함객체초기화, 참조초기화, 상수초기화 이외에는 별로 사용해본적도 없고요.

예로 드신 경우 이외에도 초기화 리스트를 써야만 하는 예를 들면
struct S
{
    S(int);
};

struct T
{
    T() { s_ = 0; }  // error. should be T() : s_(0) { }
    S s_;
};

이 코드는 컴파일 에러입니다. 초기화 리스트가 없다는 것은 멤버의 디폴트 생성자를
통하여 초기화하겠다는 것인데, S에는 그것이 없기 때문입니다. S를 상속받는
클래스에서도 같은 얘기를 할 수 있고요.

물론 가독성 측면에서 초기화 리스트보다 대입이 더 좋은 경우도 있습니다. 예를 들어
int형 멤버를 다수 갖고 있고 그것을 모두 0으로 초기화하고 싶을 때 대입을 쓴 코드가
읽기 좋습니다. 또 배열 멤버에는 초기화 리스트를 사용할 수 없고요.

요약하면 가능한 한 대입보다는 초기화 리스트를 사용하라는 것이 권장되는 스타일입니다.

corba의 이미지

추가로 초기화 리스트가 더 예외에 안전하다고 하더군요...

pool007의 이미지

off topic 성이 될 수 있어 조심스럽지만, EC++ 이 맞습니다 :-)

--
Passion is like genius; a miracle.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.