예약된 로컬 메모리 공간 (일반적으로 1MB 이하) 컴파일 옵션으로 설정가능
함수 호출과 반환이 스택에서 일어남.
단순히 스택포인터를 옮기면서 동작
스택에 큰 개체를 많이 넣으면..
void PrintVectors(const Vector& a, const Vector& b)
{
Vector* result = new Vector; //-> 힙에 할당
result->mX = a.mX + b.mX;
result->mY = a.mY + b.mY;
//... 기타 코드들..
delete result;
}
void Foo()
{
PrintVectors(a, b);
}
함수안에서 new 키워드로 힙에 생성하는건 안좋은습관.
because
vector[] list = new Vector[10]; //java 코드
vector* list = new Vector[10]; //c++코드
자바는 10개의 벡터포인터가 생성되고 그 포인터배열의 첫번째 주소를 list 가 가리키게 된다.
c++ 은 힙에 정말 10개의 벡터공간이 할당되고 list 는 첫번째 벡터의 주소를 가리키게됨.
//java code
Vector a = new Vector();
//...
// 즉시 메모리를 해제하진않음. 나~중에 가비지컬렉터가 해제함
a = null;
//c++ code
Vector* a = new Vector;
Vector* list = new Vector[10];
//...
delete a; //메모리가 즉시 해제됨
a = NULL; // 안해도됨
// 하지만 minishell 프로젝트 당시 특정 포인터가 할당되었는 확인할때
// 위쪽코드에서 할당하고 해제했으나 밑코드에서 if(a) 로만 메모리 할당여부를 판별하면 큰일날 수는 있음.
delete[] list; // []<- 꼭 넣어야됨.
list = NULL;
java, c# 은 클래스 초기화시 멤버변수 0으로 알아서 초기화함.
c++ 은 초기화 안함. →성능중시.
class X
{
const int mNameSize;
AnotherClass& mAnother;
X(AnotherClass& another)
: mNameSize(20)
, mAnother(another)
{
}
};
초기화 리스트
class Vector
{
private:
int mX;
int mY;
};
void Foo()
{
Vector a;
Vector b(10, 2);//컴파일 에러
}
class Vector
{
private:
int mX;
int mY;
public:
Vector(int x, int y);
};
void Foo()
{
Vector a; //컴파일 에러
Vector b(10, 2);//ok
}
c++ 은 생성자가 정의되어있을때 기본생성자를 제공하지않음.
// const 메서드. 해당 개체 안의 어떠한 것도 바꾸지않음
int GetX() const;
c++ 에서는 구조체를 클래스처럼 쓸 수 있음
struct는 순수하게 데이터 뿐이여야 함
차이는 private public 접근제어자 유무.
class Vector
{
public:
Vector(const Vector& other);
private:
int mX;
int mY;
};
Vector::Vector(const Vector& other)
: mX(other.mX)
, mY(other.mY) // private 멤버변수이지만 같은클래스이기때문에 접근가능
{
}
다른 개체를 이용해서 새로운 개체를 초기화
class Vector
{
private:
int mX;
int mY;
};
위 코드 컴파일시
class Vector
{
public:
Vector() {}
Vector(const Vector& other)
: mX(other.mX)
, mY(other.mY)
{
}
private:
//...
};
위와같이 컴파일러가 암시적 복사 생성자를 자동생성
ClassRecord::ClassRecord(const int *scores, int count)
: mCount(count)
{
mScores = new int[mCount];
memcpy(mScores, scores, mCount * sizeof(int));
}
//암시적 복사 생성자
ClassRecord::ClassRecord(const ClassRecord& other)
: mCount(other.mCount)
, mScores(other.mScores)
{
}
//Main.cpp
ClassRecord classRecord(scores, 5);
ClassRecord* classRecordCopy = new ClassRecord(classRecord);
delete classRecordCopy;
위 코드에서 암시적 복사생성자 수행시
메모리상황을 같이 보자면
먼저 classRecordCopy 라는 스택 포인터 공간에 new ClassRecord 주소가 할당된다.(실제 생성된 ClassRecord 클래스는 힙공간에있음.)
새로 생성된 ClassRecord 에 int mCount, int *scores 데이터를 그대로 복사해버리므로 두개의개체가 같은 포인터공간을 가리키게됨
ClassRecord::ClassRecord(const ClassRecord& other)
:mCount(other.mCount)
{
mScores = new int[mCount];
memcpy(mScores, other.mScores, mCount * sizeof(int));
}
데이터는 memcpy 로 복사하는것 좋은것같음..
Vector result = vector1 + vector2;
Vector result = vector1.operator+(vector2);
Vector Vector::operator+(const Vector& other) const
{
Vector sum;
sum.mX = mX + other.mX;
sum.mY = mY + other.mY;
return sum;
}
// X.h
class X
{
friend class Y;
private:
int mPrivateInt;
};
...
// Y.h
class Y
{
public:
void Foo(X& x);
};
...
//Y.cpp
void Y::Foo(X& x)
{
xmPrivateInt += 10;
//X.h
class X
{
friend void Foo(X& x);
private:
int mPrivateInt;
};
//GlobalFunction.cpp
void Foo(X& x)
{
x.mPrivateInt += 10;//Ok
}
//Vector.h
class Vector
{
friend std::ostream& operator<<(const std::ostream& os, const Vector& rhs);
public:
//....
private:
//....
};
//Vector.cpp
std::ostream& operator<<(std::ostream& os, const Vector& rhs)
{
os << rhs.mX << ", " << rhs.mY;
return os;
}
Vector operator+(const Vector& rhs) const;
//& 사용이유 : 굳이 클래스 복사를 할 이유가 없기때문.
//const 사용 이유: 클래스의 멤버변수가 바뀌는것도 방지
std::ostream& operator<<(const std::ostream& os, const Vector& rhs);
//ostream이 변경되기때문에 위 상황은 const 빼야됨.