객체 배열의 초기화 작동 방식

조회수 4946회
#include <iostream>
using namespace std;

class Test
{
    private:
        int num;
    public:
        Test(int n) : num(n)
        {
            cout << "Constructor : " << n << endl;
        }
        Test(const Test& copy) : num(copy.num)
        {
            cout << "Copy constructor : " << copy.num << endl;
        }
};

int main(void)
{
    Test pArray[2] = {Test(1),Test(2)};

    return 0;
}

초기화 방식이 궁금하여 테스트 해본결과 생성자를 호출 하더라구요. 기존의 객체를 이용하여 새로운 객체를 초기화를 하게 될경우는 복사 생성자를 호출하잖아요.

따라서 저기서 pArray 배열의 개별 인덱스 객체를 Test(1) ~~ 에 매치되어 초기화 되는거라면 복사 생성자를 호출해야한다고 생각합니다. 하지만 생성자를 호출 하는걸로 보아 이 경우는 아니라는 거겟죠 ?

그러면 다른 경우를 생각해보면 pArray[0],pArray[1]이 미리 생성되고 pArray[0] = Test(1); pArray[1] = Test(2); 가 된다면 개별 pArray[0],pArray[1]의 생성자 호출 2번, Test(1),Test(2) 2번 총 4번이 호출 되어야 된다고 생각을 했습니다.

그리고 객체를 초기화를 하는것이 아니라 대입을 하는것 이므로 대입연산자도 호출되어야 되는데 확인용으로 대입연산자를 구현해서 해보니 호출되지 않습니다.

어떻게 작동이 되는지 궁금합니다

  • (•́ ✖ •̀)
    알 수 없는 사용자
  • 결과만 알고싶은게 아니라 객체배열의 초기화 원리를 알고싶습니다. 알 수 없는 사용자 2016.5.18 00:41

1 답변

  • 문법적으로 배열 초기화는 그 자체로 독립적은 문법입니다.

    Test pArray[2] = {Test(1),Test(2)};
    

    와 다음은 전혀 다른 개념입니다.

    pArray[0] = Test(1);
    pArray[1] = Test(2);
    
    1. 배열은 원소들로 구성됩니다. 원소가 정의되지 않은 배열을 구성할 수 없습니다.
    2. 배열 초기화 문법 { ... } 는 이 자체가 배열 생성의 개념이며,
    3. 1의 이유 때문에, 배열의 각 인덱스에 할당될 객체에 대한 생성자를 각각 호출해야만합니다.
    4. 질문자가 말한대로 라면, 원소가 없는 배열이 존재가능해야 합니다. 하지만 이러한 배열은 존재할 수 가 없습니다.
    5. 배열원소에 대한 생성자 생략이 가능한 경우는 기본생성자(인자가 없는 생성자)를 가진 경우에만 가능합니다.

    예를 들이 초기화 문장을 사용하지 않는 다음의 경우.

    Test pArray[2];
    

    위는 실제로 다음의 의미와 동일합니다.

    Test pArray[2] = {Test(),Test()}
    

    이유는 pArray 배열은 Test 객체로 구성된 배열입니다. 즉 배열이 완성되기 위해서는 필히, 배열의 원소들도 생성되어야만 하는 겁니다. 이는 일반 타입의 경우에도 마찬가지입니다. 일반 타입의 경우에서도 마찬가지 입니다.

    int iArray[2]; 
    // 다음과 동등함
    int iArray[2] = { 0, 0 }; // int의 기본값이 0이기 때문에 동등합니다. (컴파일러에 최적화에 따라서는 0으로 초기화하지 않을 수 있습니다.)
    

    만약 Test 클래스에 기본생성자가 없다면, 이는 기본값이 없는 것입니다. 즉 어떤 생성자를 호출해야되는지 알 수가 없음으로, 문법적으로 볼 때, 초기화 문장에서 모두 생성자를 명시해주어야만 합니다.

    • 글은 이해되었으나 제가 궁금했던거 말고 몰랐던걸 기분좋게 알게 된것 같습니다.Test pArray[2] = {Test(1),Test(2)}; 에 의해 pArray가 초기화가 될텐데 이때 어떤 방식의 초기화인지 대입도 아니고 복사생성도아니라 생성인데 전에 물어봤던거와 같이 이해해도되는건가요 ? Test(1),Test(2)의 경우는 임시객체 이므로 pArray[0],pArray[1]에 복사생성 되지않고 pArray[0],pArray[1]로 불려지는걸로 ? 알 수 없는 사용자 2016.5.18 01:42
    • 그렇게 이해해도 무방하지만, 많이 다릅니다. 배열 원소에 대한 생성자를 지정하지 않으면, 배열을 생성할 수가 없습니다. 오히려 변수한개를 초기화하는 것과, 변수를 동시에 초기화하는 방법이 있다고 가정할 때, 배열초기화는 같은 이름을 갖는 여러개의 변수를 동시에 초기화하는 방법에 해당합니다. 허대영(소프트웨어융합대학) 2016.5.18 01:45
    • 아..이해했습니다.. 개별 원소에 대한 개별적인 생성자를 지정해준다는 말에서 이해가 된것같습니다.그러면 pArray[0]은 Test(1)의 생성자에 의해 생성되는거고 pArray[1]은 Test(2)의 생성자에 의해 생성되는거라고 생각하면 맞는건가요 ? 알 수 없는 사용자 2016.5.18 01:47
    • 네 맞습니다. :) 허대영(소프트웨어융합대학) 2016.5.18 01:51
    • 이 시간까지 정말로 감사드립니다 ㅠㅠ 책으로 보면 세부적인것까지 궁금해지는데 책에 설명이 너무 부족한것같습니다. 코드를 이해하는데는 문제가 안되지만 재대로 알지 못하고 겉만 아는것같아서.. !! 감사합니다 !! 알 수 없는 사용자 2016.5.18 01:53
    • 이러한 내용은 책에 자세히 나와있지않는데 어떻게 알게되는건가요 ? 다른 서적이나 검색이 답인건가요 ? 알 수 없는 사용자 2016.5.18 02:15
    • 원론적인 이야기일 수는 있지만, 언어를 사용한다는 입장보다 언어를 만들거나 개선하려는 입장에서 바라보면 도움이 됩니다. 언어학적인 관점에서 바라보면, 몇가지 대원칙이 있고 그 원칙을 따르는 소원칙들을 발견할 수 있을 겁니다. 이러한 훈련이 반복되면, 책에 있는 내용들이 이해하기 쉬울겁니다. 그렇게하기 위해서는 언어를 많이 사용해보고, 여러가지 언어를 비교하는 것이 가장 좋은 훈련이 됩니다. 이러한 훈련과 더불어 이론적 배경(컴파일러, 컴퓨터구조 등)이 받쳐주면, 누군가에게 설명하는 것도 쉬워질 겁니다. 허대영(소프트웨어융합대학) 2016.5.18 12:08
    • 감사합니다 ! ㅠㅠ 알 수 없는 사용자 2016.5.18 15:28

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)