2013-04-02 3 views
0

행렬처럼 동작해야하는 클래스가 있습니다. 는 그래서 유스 케이스는 같은 것입니다 :행렬과 같은 클래스의 딥 복사

Matrix matrix(10,10); 
matrix[0][0]=4; 
//set the values for the rest of the matrix 
cout<<matrix[1][2]<<endl; 

코드 : 나는 a 그 순간에이 같은 값을 가질 것, 매트릭스의 새로운 인스턴스를 생성 할 const Matrix b = a;를 호출하여

#include <iostream> 
#include <cstdlib> 
#include <cstdio> 
#include <cstring> 
#include <sstream> 

using namespace std; 

class Matrix { 
public: 


    Matrix(int x, int y); 

    class Proxy { 
    public: 

     Proxy(int* _array) : _array(_array) { 
     } 

     int &operator[](int index) const { 
      return _array[index]; 
     } 
    private: 
     int* _array; 
    }; 

    Proxy operator[](int index) const { 
     return Proxy(_arrayofarrays[index]); 
    } 
    Proxy operator[](int index) { 
     return Proxy(_arrayofarrays[index]); 
    } 

    const Matrix& operator=(const Matrix& othersales); 

private: 
    int** _arrayofarrays; 
    int x, y; 
}; 

Matrix::Matrix(int x, int y) { 
    _arrayofarrays = new int*[x]; 
    for (int i = 0; i < x; ++i) 
     _arrayofarrays[i] = new int[y]; 
} 

const Matrix& Matrix::operator=(const Matrix& othermatrix) { 
    new (this) Matrix(x, y); 
    for (int i = 0; i < 3; i++) 
     for (int j = 0; j < 3; j++) 
      _arrayofarrays[i][j] = othermatrix._arrayofarrays[i][j]; 

    return *this; 
} 

int main() { 

    Matrix a(2, 3); 
    a[0][0] = 1; 
    a[0][1] = 2; 
    a[0][2] = 3; 
    a[1][0] = 4; 
    a[1][1] = 5; 
    a[1][2] = 6; 

    cout << a[1][2] << endl; 
    //prints out 6 


    const Matrix b = a; 
    cout << b[1][2] << endl; 

    a[1][2] = 3; 

    cout << a[1][2] << endl; 
    // prints out 3 
    cout << b[1][2] << endl; 
    // prints out 3 as well 
} 

. 그러나 a의 값을 변경하면 b이 영향을받습니다. 따라서 a에서 일부 값을 변경하면 b도 변경됩니다. 그리고 나는 그것이 이처럼 행동하는 것을 원하지 않습니다.

a 자체의 영향을받지 않는 b 복사본을 만들어야합니다.

사람들은,하지만 나를 위해, 바보 같은 질문 수 있습니다

+2

[마지막 질문의 답변] (http://stackoverflow.com/a/15753838/16287)을 다시 확인하십시오. 비 const 객체의 경우 operator [] (int index), const 객체의 경우에는 operator [] (int index) const가 필요합니다. 그 중 하나만 가지고 있습니다. –

+0

당신은 상수로 객체를 선언 할 수 없습니다. –

+0

@DrewDormann 맞습니다. 이것을 구현하는 것을 잊었습니다. 내 게시물을 수정하겠습니다. 그럼에도 불구하고 값은 원래 개체의 변경 사항에 의해 영향을 받고 있습니다. – Dworza

답변

1

이 구현에 몇 가지 문제가 있습니다 ... 어떤 도움이 조언을 주셔서 감사합니다, 그래서 모든 물건은 정말 혼란 ++ 초보자 자바 남자와 C 등 . 단순한 것은 당신이 얻는 오류입니다 ...

Matrix 클래스에서 operator[]은 const가 아닌 멤버 함수입니다. 이는 const가 아닌 객체에서만 실행될 수 있음을 의미합니다. 은 const &에 의해 오른쪽 개체를 가져 오므로 operator[]으로 전화 할 수 없습니다. 여기서 문제는 객체를 수정하지 말 것을 약속하는 operator[]의 구현을 제공하지 않는다는 것입니다. 일단 객체를 유형에 추가하면 컴파일해야합니다.

그보다 더 중요한 사실은 당신이 기억을 새고 있다는 사실입니다. 개체에 operator=을 호출하면 이전에 보유한 메모리를 해제하지 않고 다른 Matrix을 제자리에 만듭니다. 그것은 메모리 누수입니다.

operator=의 구현은 스레드로부터 안전하지 않습니다. 내부 배열 중 하나에 대한 메모리 할당이 실패하고 예외가 발생하면 객체를 원래 상태 또는 유효한 상태가 아닌 상태로 둡니다. 이것은 그 자체로 나쁘다. 앨리어싱가있는 경우 이전에 관련

은 하나를 수정하는 것은 아마 다른 리드만큼에, operator=의 구현은 당신의 경우 자체 할당 실패, 즉, 안전하지 않습니다. 첫 번째 라인은 메모리를 누설하고 새로운 버퍼를 생성 할 것이며, 그곳에서 원래의 정보를 잃어 버리는 새로운 버퍼를 복사 할 것입니다.

마지막으로, operator[]을 사용하는 요구 사항을 삭제하고 대신 두 개의 인덱스로 operator()을 사용하면 유형 구현이 향상 될 수 있습니다. 사용자 코드는 적응되어야하며 (양방향 배열처럼 보이지는 않지만) 좀 더 표현의 자유를 제공합니다 (원하는 방식으로 내부적으로 정보를 저장할 수 있음). 동시에 포인터의 배열을 할당 한 다음 int의 N 배열을 할당 할 필요가 없습니다.NxM ints의 단일 메모리 할당을 수행하고 각 위치를 주소 지정하는 포인터 연산 (operator[]/operator()과 독립적 임)을 수행하면 메모리 풋 프린트가 줄어들고 레이아웃이보다 소형화되어 캐시 성능이 향상됩니다 (그 순간에 같은 값을 가질 것, 내가 매트릭스의 새로운 인스턴스를 생성 할 const Matrix b = a;를 호출하여

) M의 요인에 의해 동적 할당의 수를 감소 언급. 그럼에도 불구하고 b는 a의 값을 변경함으로써 영향을 받는다.

글쎄, 이것은 내가 처음 읽었던 또 다른 문제점입니다. const Matrix b = a;이라는 표현식은 operator=이 아니라 복사 생성자입니다. google에 또 다른 것 : 3의 규칙 (기본적으로 복사 생성자, 할당 또는 소멸자 중 하나를 수동으로 구현하는 경우 3 가지 모두를 구현하는 것이 좋습니다). 자신의 복사 생성자를 정의하지 않으면 컴파일러에서 얕은 복사본 (즉, Matrix에 저장된 포인터를 복사하지만 메모리를 할당하지 않음)을 암시 적으로 정의합니다. 복사가 완료되면 Matrix공유 같은 메모리가 있고 소멸자가 메모리를 해제하면 두 번째 소멸자가 실행될 때 정의되지 않은 동작을 실행하고 이미 삭제 된 메모리 인 delete []을 시도합니다.

+0

귀하의 게시물을 보내 주셔서 감사 드리며, 왜 내가 그런 식으로 구현했는지. 1)'const' 객체를 처리 할 수 ​​있도록 내 게시물을 편집했습니다. 2) 사본을 만들고 그것을 파괴하지 않고 원본을 버리는 것은 의도가 아닙니다. 그것은 정상적인'=', 즉'int a, b; a = 3; b == 3' ... next'a = 4;'그러나 여전히'b == 3', 아시다시피, 나는 의미한다. 3) 우리는 숙제를 해결하려고 노력하고 있기 때문에'()'를 사용할 수 없다. 여기서 우리는 색인 생성을 사용해야한다. – Dworza

+1

@Dorza : re. 2) 나는 기억을 누출하거나 다른 조건 (자체 할당, 예외) 하에서 할당을 안전하지 못하게하려는 의도는 절대로 생각하지 않는다. 그러나 두 가지 상황에서 클래스의 구현이 안전하지 않다는 사실은 결코 아니다. 메모리가 누수됩니다. BTW, 두 이슈를 모두 해결하는 일반적인 관용구는 * copy-and-swap * (google it)입니다. 메모리 레이아웃에 대한 주석은 인터페이스가'operator()'또는'operator []'를 사용하는지에 관계없이 여전히 내부적으로 다른 방식으로 메모리를 관리 할 수 ​​있습니다. –

+0

@Dworza : 왜 그 행동을하는지 설명하는 내용이 업데이트되었습니다. 복사 생성자를 구현해야합니다. –