2010-03-20 3 views
1

C++에서 객체 배열을 처리하는 것에 대해 약간 혼란 스럽습니다. 객체가 전달되는 방식 (참조 또는 값)과 해당 객체를 전달하는 방법에 대한 정보를 찾을 수없는 것처럼 보입니다. 배열에 저장됩니다.C++에서 동적 객체 배열 정리

개체 배열을 해당 개체 형식에 대한 포인터 배열로 기대할 수 있지만이 위치는 어디에도 쓰이지 않습니다. 그것들은 포인터가 될 것인가, 객체 자체가 배열의 메모리에 배치 될 것인가?

아래 예제에서 사용자 정의 클래스 인 myClass는 문자열을 유지합니다 (이 변수는 가변 크기로 만들거나 문자열 객체가 문자열에 대한 포인터를 보유하므로 일정한 공간을 차지합니다.) myContainer 내에서 myClass 객체의 동적 배열 myContainer.addObject() 메서드에서 더 큰 배열을 만들고 모든 객체를 새 객체와 함께 복사 한 다음 이전 객체를 삭제하려고합니다. 내 소멸자 제대로 내 기억을 정리하고있어 확신 - 나는이 지역에서 할 수있는 것을 개선

class myClass 
{ 
    private: 
      string myName; 
      unsigned short myAmount; 

    public: 
     myClass(string name, unsigned short amount) 
     { 
      myName = name; 
     myAmount = amount; 
     } 

    //Do I need a destructor here? I don't think so because I don't do any 
    // dynamic memory allocation within this class 
}; 



class myContainer 
{ 
    int numObjects; 
    myClass * myObjects; 

    public: 
    myContainer() 
    { 
     numObjects = 0; 
    } 

    ~myContainer() 
    { 
     //Is this sufficient? 
     //Or do I need to iterate through myObjects and delete each 
     // individually? 
     delete [] myObjects; 
    } 


    void addObject(string name, unsigned short amount) 
    { 
     myClass newObject = new myClass(name, amount); 

     myClass * tempObjects; 
     tempObjects = new myClass[numObjects+1]; 
     for (int i=0; i<numObjects; i++) 
      tempObjects[i] = myObjects[i]); 
     tempObjects[numObjects] = newObject; 
     numObjects++; 
     delete newObject; 

     //Will this delete all my objects? I think it won't. 
     //I'm just trying to delete the old array, and have the new array hold 
     // all the objects plus the new object. 
     delete [] myObjects; 
     myObjects = tempObjects; 
    } 
}; 

답변

3

a C++의 rray는 메모리에 배열 된 객체의 배열입니다. 에서 그래서 예를 들면 :

struct pair { 
    int x; int y; 
}; 
... 
pair array[10]; 

배열의 각 항목이 두 INT의 크기가 될 것입니다. 당신은 포인터의 배열을 원하는 경우에 당신은 단순히 하나를 선언 할 수

pair* array_of_pointers[10]; 

문자열 객체는 문자열의 가변 크기 부분에 대한 포인터를 가지고있다. 그래서 그들은 안전합니다. 사실 그들은 여기에서 중요한 교훈입니다. 과도한 메모리 처리를 피하기 위해 문자열 클래스를 사용하는 것과 같은 방법으로 벡터 클래스를 사용하여 동적 배열을 처리하는 모든 문제를 피할 수 있습니다.

연습용으로 사용하는 경우입니다. 다음은 몇 가지 문제입니다. 없이 newObject을 로컬로 할당해야합니다. 이렇게하면 코드가 정확 해지고 (newObject은 포인터가 아니기 때문에 new이 포인터를 반환하므로) 메모리를 명시 적으로 처리하는 번거 로움을 덜어줍니다. (더 고급 노트에서는 코드 위치를 한 번 더 추가하면 안전합니다.) myObject은 초기화되지 않습니다. 그리고 생성자에서 초기화 목록을 사용하지 않습니다. 생성자는 다음과 같아야합니다.

myContainer() : numObjects(0), myObjects(NULL) 
{ 

} 

코드의 소멸자는 정확히 같아야합니다.

+0

고마워, 그게 정확히 내가 뭘했는지, 그리고 난 myObjects NULL로 initialising 고려하지 않았다 (내 실제 코드 numObjects 0이면 myObjects 액세스하지 못하도록 논리가 있지만 자격을 향상시키고 주석을 추가하는 것을 잊었습니다 to say 나는 그렇게 했어) 난 구조체를 C#에서만 사용했다. C#과 C++의 구조체간에 중요한 차이점이 있습니까? –

+0

예. C++의 struct는 클래스와 비슷하지만, 다르게 말할 때까지는 모든 것이 'public'입니다. (클래스에서 디폴트는'private'입니다.) 아주 작고 간단한 데이터 타입을 정의 할 때 C++에서'struct'라는 단어를 사용하는 경향이 있습니다. C#에서는이 두 가지가 더 큰 차이가 있습니다. 'struct '는 상속 될 수 없으며 값으로 전달됩니다 (일반 클래스와 달리). 아마도 내가 잊어 버린 몇 가지 차이점이 더있을 것입니다. 기본적으로 C#에서는 성능상의 이유로 단순하고 작은 객체를 사용합니다 (좋은 예는 그래픽 목적의 짧은 벡터입니다). – Shiroko

+0

구문이 틀리면'pair array [10];과'pair * array_of_pointers [10];'이어야합니다. – fredoverflow

3

아니, 동적 배열은 해당 유형에 대한 포인터의 배열하지 않는 경우 - 그것의 포인터 첫 번째 요소. 요소는 메모리에 연속적으로 배치되고 배열이 delete[] 일 때 파괴됩니다.

따라서 할당 해제는 괜찮습니다. myClass 동적 배열을 만들면 delete 개를 개별적으로 만들 필요가 없습니다. (동적으로 할당 된) 객체에 대한 포인터 배열이있는 경우에만이 작업을 수행해야합니다.

이 결정적인 오류는하지만 있습니다

tempObjects[numObjects] = newObject; // assign a myClass pointer to a myClass instance? 

이 예를 들어 있어야한다 :

tempObjects[numObjects] = myClass(name, amount); 

또한, myObjects가 초기화되지 않습니다, 그것은 정의로 연결 사용/쓰레기와 역 참조를 포함 의미 행동.

마지막으로 학습을 위해이 작업을 수행하지 않는 한 모든 작업을 이미 완료 한 std::vector과 같은 컨테이너를 사용하면됩니다.

+0

대단히 감사합니다. 포인터/인스턴스 불일치를 고려하지 않았습니다. 내 코드를 제거하고 명료성을 변경했습니다. 실제 버전에는 myObject에 액세스하지 못하도록하는 몇 가지 논리가 있습니다.이 코드를 제거했음을 알리는 것을 잊어 버렸습니다 (얼마나 많은 myClass 배열에있는 객체들) 이것은 할당을위한 것이며 유틸리티 클래스가 아닌 동적 메모리 관리를 위해 동적 배열을 사용해야한다는 것을 지정했습니다. 나는 표준에서 liik : : 미래의 참고를 위해 벡터. –

+0

나는 당신을 투표 하겠지만, 나는 아직 충분한 (또는 어떤) 평판을 얻지 못했던 것으로 보인다. –

+1

도움 듣기 좋습니다. 미래의 질문 : 그러한 학업 제한을 언급하면 ​​우리는 더 나은 도움을 제공 할 수 있습니다. –

0

무슨 일이 일어나는지 테스트 해보십시오. (예, 컴파일러에 따라 다르지만 여전히 그렇습니다) ... myClass에 사용자 정의 소멸자를 추가하려고 할 수 있습니다 (필요하지 않더라도). 호출되면 "전역"카운터를 증가시킵니다. 그런 다음 배열을 삭제 한 후 카운터를 인쇄하십시오.

각 개체의 소멸자가 호출 될 것으로 예상됩니다. 객체는 상속 된 객체를 배열에 넣을 수 있도록 "by-pointers"로 저장됩니다 ("조각"을 피함).

+0

실제로이 과제의 후반부에 다른 유형의 데이터가 포함 된 두 개의 하위 클래스가 배열에 저장되므로 매우 유용합니다. 이 경우 myClass는 myContainer 내에 완전히 포함 된 유틸리티 클래스이며 확장되지 않습니다. 그래서 값 배열이 포인터 배열보다 적합하다고 생각합니다. 나는 포인터를 따르는 것과 관련된 추가 오버 헤드와 포인터 자체를 저장하는 데 필요한 추가 메모리가 있다고 가정합니다 (이것은 할당을위한 작은 프로젝트이며 성능은 문제가 아닙니다. 여전히 고려해야 할 사항입니다). –

1

개체 배열을 해당 개체 형식에 대한 포인터 배열로 기대할 수 있지만이 위치에 아무 것도 기록되지 않았습니다. 그것들은 포인터가 될 것인가, 객체 자체가 배열의 메모리에 배치 될 것인가?

배열은 개체 자체로 구성됩니다. 포인터 배열을 원한다면 다음과 같이 선언해야합니다 :

myClass ** tempObjects; 
tempObjects = new myClass*[numObjects+1]; 

나는 C#이나 Java에 익숙하다고 생각 하나? 이러한 언어에서 객체는 힙에만 할당 될 수 있으며 항상 참조로 액세스됩니다.C++에서 가능하지만 C++에서는 객체를 스택에 직접 배치하거나 직접 객체 배열을 직접 만들 수도 있습니다. 아래의 예에서

는 사용자 정의 MyClass 클래스는이 변수 크기를 만들 수있는 문자열을 (보유 또는 문자열 객체는 문자열에 대한 포인터를 유지하기 때문에 공간의 일관된 금액을 걸립니까?

숫자 2 : 문자열 개체 자체의 크기는 일정하지만 힙에서 할당 된 동적 크기의 버퍼에 대한 포인터가 있습니다

코드가 잘리는 것처럼 보입니다. 코드는 다양한 방식으로 더 효율적으로 작성 될 수 있지만, 하지만 올바르게 보입니다.

+0

응답 해 주셔서 감사합니다.나는 코드를 간결하게하기 위해 코드를 약간 자르고, 효율성보다는 단순성을 목표로하고있다. 가변적 인 메모리를 필요로하는 객체는 정적으로 할당 된 메모리를 사용할 수 없기 때문에 문자열 클래스처럼 작동하고 동적으로 할당 된 메모리에 포인터를 사용해야합니다. 그러한 클래스가 소멸자에서이 메모리의 할당 해제를 캡슐화하는 한 고정 필드 크기 (성능 문제는 제외)를 가진 다른 클래스 인 것처럼 사용할 수 있어야합니다. –