By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,313 Members | 1,145 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,313 IT Pros & Developers. It's quick & easy.

auto_ptr<istream> problem

P: n/a
Hi,

I'm having a problem that I can't diagnose. I'm creating istreams of
unknown types, and want to manage them on the stack, co I'm passing
around ownership-holding pointers. Usually, I would use
std::auto_ptr<std::istream>, but it seems to be deallocating early, as
the call to read(...) below breaks.

I've condensed a test case. Using my own pointer works fine, but using
auto_ptr does not (see USE_AUTO_PTR). I solved the issue by a little
trial and error, but I don't understand the cause.

Help would be greatly appreciated. I apologise if I'm simply being
idiotic, but I've been trying to work this out for days.

I'm compiling under Visual Studio 2005 (cl.exe version 14.00.50727.42)

-- James
// ---------- Begin ptr_test.cpp ----------

#include <algorithm>
#include <istream>
#include <fstream>
#include <memory>
using namespace std;

// Ownership transfering pointer to input
stream //////////////////////

//#define USE_AUTO_PTR

#if defined(USE_AUTO_PTR)
typedef auto_ptr<istreamistream_ptr;
#else

/* Not using copy constructor in example, so I won't bother writing
* a standards compliant one here. Nor assignment operator. Instead
* I'll make them private to be sure they're not generated.
*/
template <class T>
struct ptr {
ptr( T * ptr ) : _ptr( ptr ) {}
//ptr( ptr<T& other ) : _ptr( 0 ) { swap( other ); }
~ptr() { if ( _ptr ) delete _ptr; }
T * operator->() const { return _ptr; }
private:
ptr( ptr<Tconst & );
ptr<T& operator=( ptr<Tconst & );
//void swap( ptr<T& other ) { std::swap( _ptr, other._ptr ); }
T * _ptr;
};
typedef ptr<istreamistream_ptr;

#endif

// Simple test
case ///////////////////////////////////////////////////

int main() {
istream_ptr in = new fstream( "ptr_test.cpp", ios::binary );
char ch;
in->read( &ch, 1 );
return 0;
}

// ---------- End ptr_test.cpp ----------
Jun 27 '08 #1
Share this Question
Share on Google+
4 Replies


P: n/a
ja**********@gmail.com wrote:
Hi,

I'm having a problem that I can't diagnose. I'm creating istreams of
unknown types, and want to manage them on the stack, co I'm passing
around ownership-holding pointers. Usually, I would use
std::auto_ptr<std::istream>, but it seems to be deallocating early, as
the call to read(...) below breaks.

I've condensed a test case. Using my own pointer works fine, but using
auto_ptr does not (see USE_AUTO_PTR). I solved the issue by a little
trial and error, but I don't understand the cause.
Your program below doesn't compile here on my compiler (and I wouldn't
expect it to), neither with the #define, nor without.
Help would be greatly appreciated. I apologise if I'm simply being
idiotic, but I've been trying to work this out for days.

I'm compiling under Visual Studio 2005 (cl.exe version 14.00.50727.42)

-- James
// ---------- Begin ptr_test.cpp ----------

#include <algorithm>
#include <istream>
#include <fstream>
#include <memory>
using namespace std;

// Ownership transfering pointer to input
stream //////////////////////

//#define USE_AUTO_PTR

#if defined(USE_AUTO_PTR)
typedef auto_ptr<istreamistream_ptr;
#else

/* Not using copy constructor in example, so I won't bother writing
* a standards compliant one here. Nor assignment operator. Instead
* I'll make them private to be sure they're not generated.
*/
template <class T>
struct ptr {
ptr( T * ptr ) : _ptr( ptr ) {}
//ptr( ptr<T& other ) : _ptr( 0 ) { swap( other ); }
~ptr() { if ( _ptr ) delete _ptr; }
T * operator->() const { return _ptr; }
private:
ptr( ptr<Tconst & );
ptr<T& operator=( ptr<Tconst & );
//void swap( ptr<T& other ) { std::swap( _ptr, other._ptr ); }
T * _ptr;
};
typedef ptr<istreamistream_ptr;

#endif

// Simple test
case ///////////////////////////////////////////////////

int main() {
istream_ptr in = new fstream( "ptr_test.cpp", ios::binary );
Try:

istream_ptr in(new fstream( "ptr_test.cpp", ios::binary ));

That avoids creating a temporary, for which a copy constructor would be
needed that takes a const istream_ptr as argument. std::auto_ptr doesn't
have that (and neither does your class, so it shouldn't compile either).
char ch;
in->read( &ch, 1 );
return 0;
}

// ---------- End ptr_test.cpp ----------
Jun 27 '08 #2

P: n/a
* * * * istream_ptr in = new fstream( "ptr_test.cpp", ios::binary );

Visual Studio 2005 has a buggy implementation of std::auto_ptr where
this code compiles, but has the side effect that either the memory is
deleted twice or that the memory is deleted directly after that
statement, I don't remember.

Write this instead:

istream_ptr in(new fstream( "ptr_test.cpp", ios::binary ));

Regards,
Anders Dalvander
Jun 27 '08 #3

P: n/a
On 23 Jun, 03:51, Rolf Magnus <ramag...@t-online.dewrote:
Your program below doesn't compile here on my compiler (and I wouldn't
expect it to), neither with the #define, nor without.
Thank you for pointing it out. In fact, I hadn't explicitly turned off
the "language extensions" in Visual Studio, and it was optimising away
the copy constructor without so much as a warning for my pointer
class.

For auto_ptr, it implicitly converted to auto_ptr_ref, then
constructed from that, which is fair enough. In fact, my actual
pointer class does have an implicit conversion and pseudo-copy-
constructor similar to auto_ptr, so that wasn't my problem.

I found my problem in the full program, and I show it below in the
function loadResource. Rather than (as I hoped) using
auto_ptr<istream>::auto_ptr( istream * ), the return statement is in
fact calling auto_ptr_ref<istream>::auto_ptr_ref( void * ) then
auto_ptr( auto_ptr_ref<istream& ). The pointer stored in the
auto_ptr_ref is statically cast to (auto_ptr<istream*) when it is
really a (ifstream *) at heart. Cue problems.

istream_ptr loadResource( string const & name ) {
return new fstream( name.c_str(), ios::binary );
// Above line should be the following
//return istream_ptr( new fstream( name.c_str(), ios::binary ) );
}

int main() {
istream_ptr in = loadResource( "ptr_test.cpp" );
char ch;
in->read( &ch, 1 );
return 0;
}

// ---------- Begin ptr_test.cpp ----------
#include <algorithm>
#include <istream>
#include <fstream>
#include <memory>
using namespace std;
// Ownership transfering pointer to input
stream //////////////////////
//#define USE_AUTO_PTR
#if defined(USE_AUTO_PTR)
typedef auto_ptr<istreamistream_ptr;
#else
/* Not using copy constructor in example, so I won't bother writing
** a standards compliant one here. Nor assignment operator. Instead
** I'll make them private to be sure they're not generated.
**/
template <class T>
struct ptr {
ptr( T * ptr ) : _ptr( ptr ) {}
//ptr( ptr<T& other ) : _ptr( 0 ) { swap( other ); }
~ptr() { if ( _ptr ) delete _ptr; }
T * operator->() const { return _ptr; }
private:
ptr( ptr<Tconst & );
ptr<T& operator=( ptr<Tconst & );
//void swap( ptr<T& other ) { std::swap( _ptr, other._ptr ); }
T * _ptr;
};
typedef ptr<istreamistream_ptr;
#endif
// Simple test
case ///////////////////////////////////////////////////
int main() {
istream_ptr in = new fstream( "ptr_test.cpp", ios::binary );

Try:

istream_ptr in(new fstream( "ptr_test.cpp", ios::binary ));

That avoids creating a temporary, for which a copy constructor would be
needed that takes a const istream_ptr as argument. std::auto_ptr doesn't
have that (and neither does your class, so it shouldn't compile either).
char ch;
in->read( &ch, 1 );
return 0;
}
// ---------- End ptr_test.cpp ----------
Jun 27 '08 #4

P: n/a
On 23 Jun, 13:32, Anders Dalvander <goo...@dalvander.comwrote:
* * * * istream_ptr in = new fstream( "ptr_test.cpp", ios::binary );

Visual Studio 2005 has a buggy implementation of std::auto_ptr where
this code compiles, but has the side effect that either the memory is
deleted twice or that the memory is deleted directly after that
statement, I don't remember.

Write this instead:

istream_ptr in(new fstream( "ptr_test.cpp", ios::binary ));

Regards,
Anders Dalvander
Thank you, Anders. I managed to discover this (eventually) and just
posted my description of it before I saw this post. I think this
should be a warning to anyone who wants an object to construct either
from a pointer (especially in a template) or an object with an
implicit conversion from (void *)
Jun 27 '08 #5

This discussion thread is closed

Replies have been disabled for this discussion.