문제

C++에서는 성능과 데이터 무결성의 관점에서 컬렉션을 노출하기 위한 어떤 대안이 있습니까?

내 문제는 내부 데이터 목록을 호출자에게 반환하고 싶지만 복사본을 생성하고 싶지 않다는 것입니다.Thant는 목록에 대한 참조를 반환하거나 목록에 대한 포인터를 반환하도록 했습니다.그러나 나는 호출자가 데이터를 변경하도록 허용하는 것이 마음에 들지 않으며 단지 데이터를 읽도록 허용하고 싶습니다.

  • 성능과 데이터 무결성 중 하나를 선택해야 합니까?
  • 그렇다면 일반적으로 한 방향으로 가는 것이 더 낫습니까, 아니면 경우에 따라 특정한가요?
  • 다른 대안이 있나요?
도움이 되었습니까?

해결책

RichQ의 답변 배열, 벡터 등을 사용하는 경우 합리적인 기술입니다.

서수 값으로 인덱싱되지 않은 컬렉션을 사용하는 경우...아니면 당신 생각 필요할 수도 있다 가까운 미래 어느 시점에...그런 다음 자신의 반복자 유형을 노출하고 관련 begin()/end() 행동 양식:

class Blah
{
public:
   typedef std::vector<mydata> mydata_collection;
   typedef myDataCollection::const_iterator mydata_const_iterator;

   // ...

   mydata_const_iterator data_begin() const 
      { return myPreciousData.begin(); }
   mydata_const_iterator data_end() const 
      { return myPreciousData.end(); }

private:
   mydata_collection  myPreciousData;
};

...이를 일반적인 방식으로 사용할 수 있습니다.

Blah blah;
for (Blah::mydata_const_iterator itr = blah.data_begin();
   itr != blah.data_end();
   ++itr)
{
   // ...
}

다른 팁

호출자는 컬렉션을 반복하기 위해 액세스를 원하는 경우가 많습니다.Ruby의 책에서 한 페이지를 가져와서 반복을 수업의 비공개 측면으로 만드세요.

#include <algorithm>
#include <boost/function.hpp>

class Blah
{
  public:
     void for_each_data(const std::function<void(const mydata&)>& f) const
     {
         std::for_each(myPreciousData.begin(), myPreciousData.end(), f);
     }

  private:
     typedef std::vector<mydata> mydata_collection;
     mydata_collection  myPreciousData;
};

이 접근 방식을 사용하면 내부 내용에 대해 아무 것도 노출되지 않습니다.당신도 가지다 컬렉션.

어쩌면 이런 게 있지 않을까요?

const std::vector<mydata>& getData()
{
  return _myPrivateData;
}

여기서의 이점은 C++에서 얻는 것만큼 매우 간단하고 안전하다는 것입니다.RobQ가 제안한 것처럼 이를 전송할 수 있지만 복사하지 않는 경우 다른 사람이 이를 방지할 수 있는 방법은 없습니다.여기서는 다음을 사용해야 합니다. const_cast, 찾고 있다면 꽤 쉽게 찾을 수 있습니다.

대안으로 반복자는 거의 동일한 결과를 얻을 수 있지만 더 복잡합니다.여기에서 반복자를 사용함으로써 얻을 수 있는 유일한 추가 이점(내가 생각할 수 있는 것)은 더 나은 캡슐화를 가질 수 있다는 것입니다.

const 참조 또는 공유 포인터를 사용하면 기본 컬렉션의 내용이 시간이 지나도 변경되지 않는 경우에만 도움이 됩니다.

당신의 디자인을 고려하십시오.호출자가 실제로 내부 배열을 확인해야 합니까?호출자가 객체에게 배열로 무엇을 할지 지시하도록 코드를 재구성할 수 있습니까?예를 들어, 호출자가 배열을 검색하려는 경우 소유자 개체가 이를 수행할 수 있습니까?

결과 벡터에 대한 참조를 함수에 전달할 수 있습니다.일부 컴파일러에서는 코드가 약간 더 빨라질 수 있습니다.

먼저 재설계를 시도하고, 두 번째로 깨끗한 솔루션을 사용하고, 세 번째(필요한 경우) 성능을 최적화하는 것이 좋습니다.

@Shog9와 @RichQ 솔루션의 장점 중 하나는 컬렉션 구현에서 클라이언트를 분리한다는 것입니다.

컬렉션 유형을 다른 것으로 변경하기로 결정하더라도 클라이언트는 계속 작동합니다.

원하는 것은 전체 데이터 덩어리를 복사하지 않고 읽기 전용 액세스입니다.몇 가지 옵션이 있습니다.

첫째, 위에서 제안한 대로 데이터 컨테이너가 무엇이든 상관없이 const 참조를 반환할 수 있습니다.

const std::vector<T>& getData() { return mData; }

이는 구체성의 단점이 있습니다.클래스의 인터페이스를 변경하지 않고는 내부적으로 데이터를 저장하는 방법을 변경할 수 없습니다.

둘째, 실제 데이터에 대한 const 포인터를 반환할 수 있습니다.

const T* getDataAt(size_t index)
{
   return &mData[index];
}

이는 좀 더 좋지만 getNumItems 호출을 제공하고 범위를 벗어난 인덱스로부터 보호해야 합니다.또한 포인터의 불변성은 쉽게 제거되며 이제 데이터를 읽고 쓸 수 있습니다.

또 다른 옵션은 한 쌍의 반복자를 제공하는 것인데, 이는 좀 더 복잡합니다.이는 포인터와 동일한 장점을 가지며 (반드시) getNumItems 호출을 제공할 필요가 없으며 반복기의 상수성을 제거하는 데 훨씬 더 많은 작업이 필요합니다.

아마도 이를 관리하는 가장 쉬운 방법은 Boost Range를 사용하는 것입니다.

typedef vector<T>::const_iterator range_iterator_type;
boost::iterator_range< range_iterator_type >& getDataRange()
{
    return boost::iterator_range(mData.begin(), mData.end());
}

이는 다음에서 볼 수 있듯이 범위를 구성하고 필터링할 수 있다는 장점이 있습니다. 웹사이트.

const를 사용하는 것은 합리적인 선택입니다.공유 포인터 구현을 위해 Boost C++ 라이브러리를 확인해 볼 수도 있습니다.이는 포인터의 장점을 제공합니다.참조가 허용하지 않는 "null"에 대한 공유 포인터를 반환해야 할 수도 있습니다.

http://www.boost.org/doc/libs/1_36_0/libs/smart_ptr/smart_ptr.htm

귀하의 경우 쓰기를 금지하기 위해 공유 포인터의 유형을 const로 만들 수 있습니다.

당신이 가지고 있다면 std::list 일반 오래된 데이터(.NET에서 '값 유형'이라고 부르는 것)의 경우 해당 목록에 대한 const 참조를 반환하는 것은 괜찮습니다(예: const_cast)

당신이 가지고 있다면 std::list 포인터(또는 boost::shared_ptr's) 그러면 항목이 아닌 컬렉션 수정만 중지됩니다. ~에 컬렉션.내 C++은 너무 녹슬어서 이 시점에서 이에 대한 답을 말할 수 없습니다. :-(

나는 다음과 같이 콜백을 사용하는 것이 좋습니다. EnumChildWindows.사용자가 데이터를 변경하는 것을 방지할 수 있는 몇 가지 수단을 찾아야 합니다.어쩌면 const 포인터/참조.

반면에, 매번 복사본을 덮어쓰면서 각 요소의 복사본을 콜백 함수에 전달할 수 있습니다.(전체 컬렉션의 복사본을 생성하고 싶지는 않습니다.한 번에 한 요소씩 복사하는 것이 좋습니다.많은 시간/메모리가 필요하지 않습니다.)

MyClass tmp;
for(int i = 0; i < n; i++){
    tmp = elements[i];
    callback(tmp);
}

다음 두 기사에서는 컨테이너 클래스 캡슐화와 관련된 몇 가지 문제와 필요성에 대해 자세히 설명합니다.완벽하게 작동하는 솔루션을 제공하지는 않지만 본질적으로 Shog9에서 제공하는 것과 동일한 접근 방식으로 이어집니다.

1 부: 캡슐화와 뱀파이어
2부(이 글을 읽으려면 무료 등록이 필요합니다): 열차 잔해 발견
케블린 헤니

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top