Ok, I'm getting frustrated, and things aren't working. And it is unclear to me why. I'm struggling with this, and the calls aren't making sense to me.
Using a basic I/O class (based on the version from Sam Cragg), I created the following class:
class asCOScriptStream{ public: asCOScriptStream(); asCOScriptStream(const std::string&); ~asCOScriptStream(); asCOScriptStream& operator=(const asCOScriptStream&); template<class T> void write(T); void open(const std::string&); void close(void); bool good(void); static bool RegisterCOScriptStream(asIScriptEngine*); private: bool isFile; std::ostream * _stream;};
I register the constructors, destructor, and operators with:
bool asCOScriptStream::RegisterCOScriptStream(asIScriptEngine* engine){ int r = 0; // Register the ofstream type r = (r < 0) ? r : engine->RegisterObjectType("ofstream", sizeof(asCOScriptStream), asOBJ_CLASS_CDA); // Register the constructors r = (r < 0) ? r : engine->RegisterObjectBehaviour("ofstream", asBEHAVE_CONSTRUCT, "void f()", asFUNCTIONPR(ConstructOstream, (asCOScriptStream*), void), asCALL_CDECL_OBJFIRST); r = (r < 0) ? r : engine->RegisterObjectBehaviour("ofstream", asBEHAVE_CONSTRUCT, "void f(const string ∈)", asFUNCTIONPR(ConstructOstream, (asCOScriptStream*, const std::string&), void), asCALL_CDECL_OBJFIRST); // Register the destructor r = (r < 0) ? r : engine->RegisterObjectBehaviour("ofstream", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructOstream), asCALL_CDECL_OBJFIRST); // Register the assignment operator r = (r < 0) ? r : engine->RegisterObjectBehaviour("ofstream", asBEHAVE_ASSIGNMENT, "ofstream &f(const ofstream ∈)", asMETHODPR(asCOScriptStream, operator =, (const asCOScriptStream&), asCOScriptStream&), asCALL_THISCALL); // Register the manipulators r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, ios_manip)", asFUNCTIONPR(InsertOperator<asCScriptStreamManip::ios_manip>, (asCOScriptStream*, asCScriptStreamManip::ios_manip), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, ostream_manip)", asFUNCTIONPR(InsertOperator<asCScriptStreamManip::ostream_manip>, (asCOScriptStream*, asCScriptStreamManip::ostream_manip), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, set_manip)", asFUNCTIONPR(InsertOperator<asCScriptStreamManip::set_manip>, (asCOScriptStream*, asCScriptStreamManip::set_manip), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, set_fill)", asFUNCTIONPR(InsertOperator<asCScriptStreamManip::set_fill>, (asCOScriptStream*, asCScriptStreamManip::set_fill), asCOScriptStream*), asCALL_CDECL); // Register the inserters r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, bool)", asFUNCTIONPR(InsertOperator<bool>, (asCOScriptStream*, bool), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, uint)", asFUNCTIONPR(InsertOperator<unsigned long>, (asCOScriptStream*, unsigned long), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, uint16)", asFUNCTIONPR(InsertOperator<unsigned short>, (asCOScriptStream*, unsigned short), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, uint8)", asFUNCTIONPR(InsertOperator<unsigned char>, (asCOScriptStream*, unsigned char), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, int)", asFUNCTIONPR(InsertOperator<long>, (asCOScriptStream*, long), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, int16)", asFUNCTIONPR(InsertOperator<short>, (asCOScriptStream*, short), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, int8)", asFUNCTIONPR(InsertOperator<char>, (asCOScriptStream*, char), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, bits)", asFUNCTIONPR(InsertOperator<unsigned long>, (asCOScriptStream*, unsigned long), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, bits16)", asFUNCTIONPR(InsertOperator<unsigned short>, (asCOScriptStream*, unsigned short), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, bits8)", asFUNCTIONPR(InsertOperator<unsigned char>, (asCOScriptStream*, unsigned char), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, float)", asFUNCTIONPR(InsertOperator<float>, (asCOScriptStream*, float), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, double)", asFUNCTIONPR(InsertOperator<double>, (asCOScriptStream*, double), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, const string ∈)", asFUNCTIONPR(InsertOperator<const std::string&>, (asCOScriptStream*, const std::string&), asCOScriptStream*), asCALL_CDECL); r = (r < 0) ? r : engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SLL, "ofstream & f(ofstream ∈, string @+)", asFUNCTIONPR(InsertOperator<const std::string&>, (asCOScriptStream*, const std::string&), asCOScriptStream*), asCALL_CDECL); if ( r < 0 ) return false; return true;}
I have a template function for the insertion operator:
template<class T>staticasCOScriptStream* InsertOperator(asCOScriptStream* out, T value){ out->write(value); return out;}
And I have my constructors, destructor, and assignment operator as:
asCOScriptStream::asCOScriptStream(){ std::cerr << "asCOScriptStream default constructor called" << std::endl; _stream = &std::cout; isFile = false;}asCOScriptStream::asCOScriptStream(const std::string& fn) : isFile(true){ std::cerr << "asCOScriptStream constructor called" << std::endl; _stream = new std::ofstream(fn.c_str());}asCOScriptStream::~asCOScriptStream(){ std::cerr << "asCOScriptStream destructor called" << std::endl;}asCOScriptStream& asCOScriptStream::operator=(const asCOScriptStream& other){ std::cerr << "asCOScriptStream assignment operator called" << std::endl; _stream = other._stream; isFile = other.isFile; return *this;}
And a template function to write the value to a stream:
template<class T>void asCOScriptStream::write(T val){ // Ignore writes to closed files if ( isFile ) { std::ofstream* tmp = dynamic_cast<std::ofstream*>(_stream); if ( !tmp->good() ) return; } *_stream << val;}
Now, when I execute the following script, only the first argument is output to the file, and the remaining to the console:
void main(){ ofstream test("test.out"); test << "Test" << 0x55 << std.endl;}
I dumped out some debug showing the calls to the constructors, destructor, and assignment operators. It shows also the right hand pointer to
_stream for the assignment operator.
Address of std::cout: 0x4b4570Stream created. Pointer: 0x3da3d0asCOScriptStream::asCOScriptStream(const std::string&): this: 0x3de768 this->_stream: 0x3dac80asCOScriptStream::asCOScriptStream(): this: 0x3de568 this->_stream: 0x4b4570asCOScriptStream::operator=: this: 0x3de568 this->_stream: 0x4b4570 other: 0x3de768 other._stream: 0x3dac80asCOScriptStream::write: this: 0x3de568 this->_stream: 0x3dac80asCOScriptStream::~asCOScriptStream this: 0x3de568asCOScriptStream::asCOScriptStream(): this: 0x3de568 this->_stream: 0x4b4570asCOScriptStream::operator=: this: 0x3de568 this->_stream: 0x4b4570 other: 0x3de568 other._stream: 0x4b4570asCOScriptStream::write: this: 0x3de568 this->_stream: 0x4b4570asCOScriptStream::~asCOScriptStream this: 0x3de568asCOScriptStream::asCOScriptStream(): this: 0x3de568 this->_stream: 0x4b4570asCOScriptStream::operator=: this: 0x3de568 this->_stream: 0x4b4570 other: 0x3de568 other._stream: 0x4b4570asCOScriptStream::write: this: 0x3de568 this->_stream: 0x4b4570asCOScriptStream::~asCOScriptStream this: 0x3de568asCOScriptStream::~asCOScriptStream this: 0x3de768Destructor called
Looking at this, I'm confused why the every call to the assignment operator after the first is assigning itself to itself (ala
x=x;).
It seems to follow this progression:
1. Create test.2. Create a temporary (call it tmp).3. Assign tmp = test.4. Call tmp->write().5. Destroy tmp.6. Create a temporary (call it tmp2).7. Assign tmp2 = tmp2.8. Call tmp2->write().9. Destroy tmp2.10. Create a temporary (call it tmp3).11. Assign tmp3 = tmp3.12. Call tmp3->write().13. Destroy tmp3.14. Destry test.
The problem is on steps 7 and 11. Why is this done?
Have I setup something wrong? Or is the devil in the details, and I'm not getting the details?