복사생성자, 연산자 오버로딩 부분 이상하게 안됩니다

ehddms10의 이미지

#include<iostream>
 
using namespace std;
 
class TwoD
{
private:
	double** arr;
	double MaxRows;
	double MaxCols;
public:
	TwoD()// 가로세로 10 짜리 배열 생성
		:MaxRows(10), MaxCols(10)
	{
		arr = new double* [MaxRows];
		for (int i = 0; i < MaxRows; i++)
		{
			arr[i] = new double[MaxCols];
		}
	}
	TwoD(double a, double b)
		:MaxRows(b), MaxCols(a)
	{
		arr = new double* [MaxRows];
		for (int i = 0; i < MaxRows; i++)
		{
			arr[i] = new double[MaxCols];
		}
	}
	int getcols()
	{
		return MaxCols;
	}
	int getrows()
	{
		return MaxRows;
	}
	double operator[](int i)
	{
		return *(arr[i]);
	}
	void set(int col, int row, int value)
	{
		arr[col][row] = value;
	}
	double returnvalue(int col, int row)
	{
		return arr[col][row];
	}
	const TwoD& operator=(const TwoD& r)// c.=(a);
	{
 
		for (int i = 0; i < MaxRows; i++)
		{
			delete[] arr[i];
		}
		delete[] arr;
 
		MaxRows = r.MaxRows;
		MaxCols = r.MaxCols;
 
		arr = new double* [MaxRows];
		for (int i = 0; i < MaxRows; i++)
		{
			arr[i] = new double[MaxCols];
		}
 
		for (int i = 0; i < MaxRows; i++)
		{
			for (int j = 0; j < MaxCols; j++)
			{
				arr[i][j] = r.arr[i][j];
			}
		}
		return *this;
	}
	friend TwoD& operator+(const TwoD& a, const TwoD& b);
	void print()
	{
		for (int i = 0; i < MaxRows; i++)
		{
			for (int j = 0; j < MaxCols; j++)
			{
				cout << arr[i][j] << " ";
			}
			cout << "\n";
		}
	}
 
	~TwoD()
	{
		for (int i = 0; i < MaxRows; i++)
		{
			delete[] arr[i];
		}
		delete[] arr;
	}
};
int main()
{
	TwoD a(1, 1);
	TwoD b(1, 1);
	double s;
	cout << "a 배열 입력\n";
	for (int i = 0; i < a.getrows(); i++)
	{
		for (int j = 0; j < a.getcols(); j++)
		{
			cin >> s;
			a.set(i, j, s);
		}
	}
	cout << "b 배열 입력\n";
	for (int i = 0; i < b.getrows(); i++)
	{
		for (int j = 0; j <b.getcols(); j++)
		{
			cin >> s;
			b.set(i, j, s);
		}
	}
	TwoD c(1, 1);
	c = a;
	c.print();
	c = a + b;
	c.print();
	return 0;
}
TwoD& operator+(const TwoD& a, const TwoD& b)
{
	TwoD r(a.MaxRows, a.MaxCols);
 
	for (int i = 0; i < a.MaxRows; i++)
	{
		for (int j = 0; j < a.MaxCols; j++)
		{
			r.arr[i][j] = a.arr[i][j] + b.arr[i][j];
		}
	}
	return r;
}

위 코드는 간단히 설명하자면 nXn 크기의 이차원 배열을 만들고 +연산자와 =연산자를 오버로딩하여 이차원 배열을 만드는 클래스끼리 연산을 할 수 있게끔 만든 코드인데 이상하게 c=a는 잘 작동을 하는데 c=a+b는 위치를 읽는데 엑세스 위반이 발생합니다. 확인하는데 귀찮아서 배열의 크기는 1X1로 고정을 해두었는데 나중에 입력받은만큼의 크기로 만들 수 있게끔 바꿀겁니다. 도움이 간절합니다
익명 사용자의 이미지

당신은 C++의 금기 중 금기인, 지역 변수의 참조를 반환하는 함수를 만든 죄를 범하셨습니다.

회개하세요.

ehddms10의 이미지

일단 지역변수의 참조를 반환한 것은 제가 큰 죄를 범한것이 맞습니다 회개하겠습니다. 근데 오류가 계속 떠요. 방금 말씀 듣고 다시 디버깅을 돌리고있는데 소멸자를 없애니까 오류가 안뜨더라구요 그래서 생각한게 +연산을 하고 r 값을 return 하면 소멸자가 호출이 되면서 r값도 지우니까 delete된 r값에 =연산자가 접근을 하려니 오류가 뜬게 아닌가 싶습니다 그런데 소멸자는 유지를 해야하는데 어떻게 해야합니까인줄 알았는데 1을 때려넣어도 에러가 뜨네요 걍 arr부분이 문제인거같습니다 아 ㄹㅇ 모르겠당

익명 사용자의 이미지

C++에는 3의 법칙이라는 게 있습니다

https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)

(링크가 깨져서 올라가는데, 닫는 괄호까지 전부 복사해서 들어가세요)

만약 어떤 클래스에 아래 3개 특수 메서드 중 단 하나라도 non-default가 되도록 정의하였다면, 나머지 둘도 반드시 정의해 주어야 한다는 것입니다.

  • 소멸자
  • 복사 생성자
  • 복사 대입 연산자

귀하의 코드는 소멸자를 정의하였는데 복사 생성자와 복사 대입 연산자를 정의하지 않았군요.

======

"3의 법칙"의 rationale은, 만약 당신의 클래스가 커스텀 소멸자를 가지고 있다면
=> 그 클래스는 소멸될 때 명시적으로 해제해 주어야 하는 자원을 소유하고 있다는 뜻이고
=> 그러한 경우, 얕은 복사를 수행하는 복사 생성자와 복사 대입 연산자의 기본 동작이 적절할 가능성은 매우 낮다는 것입니다.

실제로 귀하의 클래스 TwoD는 동적 할당된 메모리 배열을 소유하고 있는데,
복사 생성자와 복사 대입 연산자는 그저 포인터만 얕게 복사할 뿐이니 문제가 되는 것이죠.
분석하신 대로, 여러 TwoD 인스턴스가 동일한 동적 메모리를 들고 있다가 먼저 소멸되는 놈이 해제해 버리고 맙니다.

이런 경우 복사 생성자와 복사 대입 연산자를 제대로, 깊은 복사를 하도록 짜 넣어야 해결됩니다.

======

C++는 날카롭고 예리한 도구입니다. 잘 쓴다면야 더할 나위 없겠지만, 그렇지 않다면 손을 베일 각오를 해야죠.

특히 C++03 이전의 옛 C++는 할 수 있지만 해선 안되는 pitfall들이 하도 많아서 사용자가 내공이 좀 있어야 합니다.

Effective C++ 시리즈 책이라도 구해다가 한 번 보시는 걸 추천드리고요.

C++11 이후의 Modern C++는 여러 면에서 개선되었습니다만, 그래서 배우기 쉬워졌느냐고 묻는다면 여전히 글쎄요...

익명 사용자의 이미지

지금 다시 봤는데 복사 대입 연산자는 정의하셨군요.

복사 생성자도 정의하세요.

ehddms10의 이미지

아 진짜 너무 감사합니다 진짜 안풀려서 힘들었었는데 아주 중요한거도 배워갑니다 지금 기분이면 공중제비를 3연속으로 돌 수 있을 것 같습니다 감사합니다

Anti-Lock의 이미지

배열 인덱스로 double 타입을 사용하는것은 문제 없을까요?
(런타임 오류가 그것 때문이라는 이야기는 아닙니다만...)

댓글 달기

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