본문 바로가기

정보정보

Effective C++ 효율!


항목 17. 효율 향상에 있어 지연평가는 충분히 고려해볼만하다!

1.참조 카운팅

 class String{....}
String s1 = "Hellow";
String s2 = s1;

->String의 복사생성자가 보통의 상식대로 만들어졌다면.
s2는 s1으로 초기화된 이후에 s1과 s2가 "Hellow" 의 사본이 동시에 가지고 있게 된다.
이때, s2 와 s1이 동일한 값을 갖기 위해 new/strcpy이 수행되어야 하므로
실행비용이 만만찮게 든다.
하지만 지금까지는 s2의 존재이유가 없다(s1이 존재하기 때문에)

그렇기 때문에 존재이유가 없는 s2를 (결국 필요로 할때까지) 복사생성자 따위를 사용하여 복사해놓지 않는다.

만약,

s1 스트링과 s2 스트링을 print 해야 하는 경우 굳이 s3 = s1+s2를 할것이 아니라
아래와 같이 그냥 print 시킴으로서 메모리의 낭비 및 string class 를 생성하지 않는 것이 좋다 

cout << s1;
cout << s1+s2;


예제

//(보통의) 일반 방식
class LargeObject {
     public :
        LargeObject(ObjectID id);
        const string& field() const;
        int field2() const
        double string3() const;
        const string& field4() const;
        const string& field4() const;
        .... 
}

void restoreAndProcessObject(ObjectID id)
{
        LargeObject object(id);    //객체를 가져옴!
        if(object.field2() ==0)
           cout<<"Error!<<end;
}

지연방식의 데이터 가져오기(Lazy Fetching)

class LargeObject {
     public :
        LargeObject(ObjectID id);
        const string& field() const;
        int field2() const
        double string3() const;
        const string& field4() const;
        const string& field4() const;
        .... 
    private:
        Object oid;
        mutable string *field1value;
        mutable int *field2value;
        mutable doube *field3value;
        mutable string *field4value;
}
LargeObject::LargeObject(ObjectID id)
:oid(id),field1value(0),filed2value(0),field3value(0),field4value(0),....
{
      if(field1value ==0)
      {
         //db에서 필드 1의 데이터를 읽고 field1value가 이 데이터를 가르키게 한다.
      }
     return *field1value;
}

의미
1) LargeObject 의 멤버함수는 자신이 사용할 data를 읽기 전에 해당 필드의 포인터 상태를 점검한다.
   포인터가 null 이라는 뜻은 해당 변수가 아직 아무일도 하지 않았다는 것을 알수있다.
2) 필드에 대한 포인터는 어떤 멤버함수에서도 실제 data를 가르키도록 해야 한다.
    이때 가장 좋은 방법은 mutable 로 선언하여 어떠한 멤버함수에서도 수정이 가능하도록 한다.


이게 무슨 효율이 좋아진다는 건지는 잘 모르겟다.

개인적으로 생각하는 효율이 좋아지는 방법은 함수의 파라미터를 복사생성자& 사용하기.
-_-.....