2010-06-24 2 views
1

작업중인 API의 경우 사용자가 ostream에 사용자 지정 개체를 삽입 할 수 있지만이 개체는 의미가 없으며 너무 많은 메모리입니다 컨텍스트에 대한 추가 포인터 또는 참조를 포함하도록 제한됩니다.C++ ostream 삽입 연산자에서 컨텍스트를 사용할 수 있도록 설정해야합니다.

사용자가 기본 컨텍스트를 초기화 가정 (. 제한된 메모리와 임베디드 시스템에서 수만 16/32/48 비트 오브젝트의 수백만의 생각), 이러한 개체 중 하나 조회 :

DDB ddb("xc5vlx330t"); 
Tilewire tw = ddb.lookUpTilewire("DSP_X34Y0", "DSP_IMUX_B5_3"); 
... 
std::cout << complexDataStructure; 

완전히 다른 범위에서 사용자의 명시 적 코드에서 멀리 중첩되어있을 수 있으므로 ddb을 사용할 수없는 경우 ostream에 개체를 삽입해야 할 수 있습니다. TW 캡슐화

os << tw; 

실제 값은 97,594,974이지만, 원하는 출력이있다 :

주문이 작동하기에 적절한 삽입 연산자 ddb에 액세스 할 필요가 있지만, 그렇지 캔
[email protected][263,84] DSP "DSP_X34Y0" ([email protected]) 

정적 또는 전역 변수 또는 함수 (멀티 스레딩 이유로)에 의존합니다. 내가 뭘 같은 을 거라고하는 요청에 사용자를 허용하고 같은 종류의 스트림 래퍼를 사용할 수 있습니다 : ostream에의 반환 서브 클래스는 특별한 스트림 삽입 기에서 사용할 DDB에 대한 참조를 포함 할 것

ostream& wrappedCout = ddb.getWrappedOstream(std::cout); 

그 그것을 필요로하고 원본 스트림에 대한 참조는 — std::cout이 경우에는 —인데 모든 출력을 전달합니다.

불행히도, 제가 상상해 보았던 상속 또는 구성 계획은 코드 작성 (엄청난 관심사가 아닌)에 문제가 될 수 있으며 사용자에게는 더 큰 관심사가 될 수 있습니다. 우아하게 ddb를 삽입 연산자에 사용할 수있게하는 방법에 대한 제안? 나는 약간 부스트를 알고있다. 유풍은 여기에서 나를 도울 것이라고 확신하지 못한다.

+0

스레드 로컬 저장소를 사용할 수 없습니까? 스레딩에 관심이 있으니 일종의 스레드 로컬을 제공하는 스레딩 라이브러리가있을 것입니다. – doublep

+0

스레드 로컬 저장소는 흥미로운 아이디어이지만 일반적으로 동일한 스레드 내에서 여러 DDB 개체가 공존 할 수 있으므로 컨텍스트를 스트림으로 래핑하는 것이 좋습니다. –

답변

1

iword/pword 메커니즘을 사용하여 ddb에 대한 참조를 저장하는 사용자 지정 스트림 조작기를 작성하십시오. 다음은 다중 스레드 프로그램에서 iwork_indexes 맵에 잠금을 추가해야하는 예제입니다. 내가 무엇을 한 번에 액세스 할 수 있으며, 무엇을 변경할 수 있습니다,하지만 이해한다면 완전히 확실하지 않다

class dbb 
{ 
public: 
    explicit dbb(int value) : m_value(value) {} 
    int value() const { return m_value; } 
private: 
    int m_value; 
}; 

class dbb_reliant_type 
{ 
public: 
    dbb_reliant_type(const std::string& value) : m_value(value) {} 
    const std::string& value() const { return m_value; } 
private: 
    std::string m_value; 
}; 

typedef std::map<std::ostream*, int> iword_map; 
iword_map iword_indexes; 

inline int get_iword_index(std::ostream& os) 
{ 
    iword_map::const_iterator index = iword_indexes.find(&os); 

    if(index == iword_indexes.end()) 
    { 
     std::pair<iword_map::iterator, bool> inserted = iword_indexes.insert(std::make_pair(&os, os.xalloc())); 
     index = inserted.first; 
    } 

    return index->second; 
} 


inline std::ostream& operator<<(std::ostream& os, const dbb& value) 
{ 
    const int index = get_iword_index(os); 

    if(os.pword(index) == 0) 
     os.pword(index) = &const_cast<dbb&>(value); 

    return os; 
} 

std::ostream& operator<<(std::ostream& os, const dbb_reliant_type& value) 
{ 
    const int index = get_iword_index(os); 
    dbb* deebeebee = reinterpret_cast<dbb*>(os.pword(index)); 
    os << value.value() << "(" << deebeebee->value() << ")"; 
    return os; 
} 

int main(int, char**) 
{ 
    dbb deebeebee(5); 
    dbb_reliant_type variable("blah"); 
    std::cout << deebeebee << variable << std::endl; 
    return 0; 
} 
+0

코드 예제를 제공해 줄 수 있습니까? 나는 그것이 어떻게 끝 났는지보고 싶다. –

+0

다음은 내가봤을 때의 예다. 나는 그것을 자세히 보지 않았지만, 계속 진행할 수있을 정도로 충분해야한다. http://www.unc.edu/depts/case/pgi/pgC++_lib/stdlibug/str_5412.htm – Gary

+0

나중에 더 많은 확장 답변 (예 : URL), 예제 코드 등 – Joe

1

는 ....이

struct TilewireFormatter { 
    DDB *ddb; 
    TilewireFormatter(DDB* d) : ddb(d) {} 

    print(std::ostream& out, const Tilewire& obj) { 
     // some formatting dependent on ddb 
     out << obj; 
    } 
}; 

과 같은 작업을 수행 할 수 있습니다 out << tw;formatter.print(out, tw)으로 대체하십시오.

그런 다음 Tilewire에 대해 < < 연산자 오버로드를 제공하지 않고 그 주위에 TilewireFormatter의 인스턴스를 전달하면 ddb의 형식에 따라 형식을 지정하는 데 사용됩니까?

+0

+1 - ddb는이 코드로 어떻게 든 살아 있어야한다는 것을 명심하십시오. –

+0

@choobablue 불행히도 객체를 전달하는 좋은 방법이 없으며,이 접근법은 사용자가 정규 스트림 시맨틱에 의존하는 것을 허용하지 않습니다 (이것은 API이므로 채택 비용이 낮아야합니다). ostream 안에 ddb를 래핑하는 것에 대한 좋은 점은 operator << (ostream & os, ...)가 free에 대한 참조를 얻는다는 것입니다. 그리고 컨텍스트에서 동적 캐스트를 사용할 수 있습니다. –

+0

@Billy ONeal DDB 개체의 수명은 이러한 호출을 모두 포함하는 것으로 간주 할 수 있습니다. –

0

삽입 연산자를 사용하는 동안 문맥 정보를 전달하는 방법을 찾기보다는 choobablue와 같은 인쇄 방법을 제안하는 것이 좋습니다. 그것은 멋지고 간단한 해결책이고 무엇인가 좋아하는 사람은 아마도 그것이 가치가있는 것보다 더 많은 문제 일 것입니다.

또한 임베디드 시스템에서 iostream을 선택하는 것이 이상하다고 생각합니다.그것들은 C++ 표준 라이브러리에서 가장 비 대한 부분 중 하나입니다. (구현뿐만 아니라 디자인에 의해서가 아니라) 임베디드 시스템에서 작업하는 경우에는 자신 만의 대안을 사용할 수 있습니다 (여전히 iostream의 기본 디자인), iostream을 효율적으로 사용하고 여러 스레드에서 사용할 때와 마찬가지로 빠르게 수행 할 수 있습니다.

+0

IOStreams가 FUD 인 이유는 무엇입니까? 나는 당신이 그것을 참조하고있는 어떤 I/O 장치가 일반적으로 병목이기 때문에 속도 제한이 문제가되는 경우를 아직 보지 못했습니다. 메탈에 가까이 가야한다면 다양한 streambuf 클래스를 사용하십시오. –

+1

@ stinky472 위의 대답이 실제로 사용자의 관점에서 보면 꽤 우아하다는 데 동의 할 것 같습니다.하지만 iostreams와 임베디드 시스템에 관해서는 당신과 함께하고 있습니다. 좀 더 완벽한 이야기는 일부 임베디드 사용자가이 임베디드를 실행해야 할 수도 있다는 것입니다.이 경우 iostreams 의존성을 분리하려고합니다. 사실, 위의 해결책은 내가 물건을 분리하는 데 도움이 될 것입니다. 또한 일반 시스템에서 실행되는 사용자의 경우 사용자의 단순성이 매우 중요합니다. –

+0

@Billy는 속도가 그렇게 빠르지 만, 제한된 리소스를 가진 임베디드 시스템의 경우, 나는 팽창에 대해 더 많이 이야기하고 있습니다. Even Sutter는이 점에 대해 심도있게 설명하고 표준위원회가 거의 변화가없는 레거시 I/O 스트림을 채택함으로써 얻은 실수를 자세히 설명합니다. 예를 들어, 가상 메소드와 템플릿의 결합은 많은 팽창을 가져옵니다. cout을 사용하는 전 세계 프로그램을 운영함으로써 실행 파일 크기를 크게 늘리는 것은 드문 일이 아닙니다. – stinky472

0

경우 내 자신의 대답을 제공, 그래서 나는이에 새로 온 게리와 신용을 공유하는 날의 방해가 잘 게리 난 그냥 이전과 같은 참조를 통해 순간 우연히 발견 한 것을 지적 : Stream Storage for Private Use: iword, pword, and xalloc

#include <iostream> 

// statically request a storage spot that can be associated with any stream 
const int iosDdbIndex = std::ios_base::xalloc(); 

class DDB { 
public: 
    // give the stream a pointer to ourselves 
    void bless(std::ostream& os) { os.pword(iosDdbIndex) = this; } 
    // provide a function that the insertion operator can access 
    int getSomething(void) { return 50; } 
}; 

class Tilewire { 
    friend std::ostream& operator<< (std::ostream& os, Tilewire tilewire); 
    // encapsulate a dummy value 
    int m; 
public: 
    // construct the Tilewire 
    Tilewire(int m) : m(m) {} 
}; 

std::ostream& operator<< (std::ostream& os, Tilewire tilewire) { 
    // look up the pointer to the DDB object 
    DDB* ddbPtr = (DDB*) os.pword(iosDdbIndex); 
    // insert normally, and prove that we can access the DDB object's methods 
    return os << "Tilewire(" << tilewire.m << ") with DDB param " << ddbPtr->getSomething(); 
} 

int main (int argc, char * const argv[]) { 
    DDB ddb; 
    ddb.bless(std::cout); 
    std::cout << Tilewire(0) << std::endl; 
    return 0; 
} 
관련 문제