Can I safely assume that vector::clear() will release the memory like I expect it to if I want to read in a different set of points?
No. std::vector<>::clear() does not do anything to free the memory pointed to by the objects it stores. If you are storing pointers, you must manually delete each pointer before clearing the vector. Likewise, you must do this with any operation that removes a vector element (erase) or replaces it with a different one (assign, operator=, etc.). Otherwise, you leak the memory occupied by the pointer that is left dangling.
Whenever I create vectors of pointers, I usually use a smart pointer instead of a raw pointer. Smart pointers use reference counting and will automatically delete themselves when the reference count reaches zero (i.e. no one is holding onto a copy of the pointer anymore). Smart pointers might be too much overhead and slow performance too much for your application. If you want to look into it, we use the smart pointer implementation from the Boost C++ Libraries.
Note also that for some implementations (Microsoft VC++ in particular), calling clear() does not actually free up the memory occupied by the vector itself. So if your vector is sized to hold 10^6 points and you then clear it, it still occupies the same amount of storage (10^6 * sizeof( ptN_t *) + a little overhead ). The only way we have found that actually reduces the size of the vector itself is to do the following:
myVector.clear();
{
std::vector< double > reallyAndTrulyEmpty;
myVector.swap( reallyAndTrulyEmpty );
}
myVector.clear();
{
std::vector< double > reallyAndTrulyEmpty;
myVector.swap( reallyAndTrulyEmpty );
}
To copy to clipboard, switch view to plain text mode
In other words, forcing a swap with a local empty vector does the trick. Simply calling clear just sets the value returned by size() to zero.
Can I check if gpstime is defined, for example?
I don't know what you mean by this. If what you want is a way to parse each line of the file to retrieve N-dimensional point data, without a multi-level if-else logic tree for each point, define a virtual method for each point type that parses the line into fields:
class ptcore_t
{
public:
ptcore_t();
virtual void clear();
// ...
/* Reimplement for each concrete type to extract type-specific fields */
virtual bool parseLine( const std::wstring & line );
private:
// ...
}
class ptcore_t
{
public:
ptcore_t();
virtual void clear();
// ...
/* Reimplement for each concrete type to extract type-specific fields */
virtual bool parseLine( const std::wstring & line );
private:
// ...
}
To copy to clipboard, switch view to plain text mode
So your file reader will basically read a line of text (if that's how it is stored), construct an object of the type stored in the file, then pass the line to that object so it can parse its contents out. You could even make a constructor that did this as part of the allocation:
ptN_t * ptr = new ptN_t( line );
ptN_t * ptr = new ptN_t( line );
To copy to clipboard, switch view to plain text mode
Alternatively, when you first open the file and determine the type of points it contains, you could construct function objects (specific for the point type) to create a point of the appropriate type and to parse the line into the member variables. The parser function object then parses the line and fills in the appropriate member variables for the pointer. The function objects basically look like this:
struct pt_t_builder
{
virtual ptcore_t * operator()() const = 0; // pure virtual, must be defined in derived structs
};
struct pt1_t_builder : public pt_t_builder
{
virtual ptcore_t * operator()() const { return new pt1_t; }
};
struct pt_t_parser
{
virtual bool operator()( ptcore_t * ptcore, const std::wstring & line ) const = 0;
};
struct pt1_t_parser : public pt_t_parser
{
bool operator()( ptcore_t * ptcore, const std::wstring & line ) const
{
pt1_t * pt1 = static_cast< pt1_t * >( ptcore );
// parse "line" into fields, store into pt1 members
// return true / false based on success
}
};
struct pt_t_builder
{
virtual ptcore_t * operator()() const = 0; // pure virtual, must be defined in derived structs
};
struct pt1_t_builder : public pt_t_builder
{
virtual ptcore_t * operator()() const { return new pt1_t; }
};
struct pt_t_parser
{
virtual bool operator()( ptcore_t * ptcore, const std::wstring & line ) const = 0;
};
struct pt1_t_parser : public pt_t_parser
{
bool operator()( ptcore_t * ptcore, const std::wstring & line ) const
{
pt1_t * pt1 = static_cast< pt1_t * >( ptcore );
// parse "line" into fields, store into pt1 members
// return true / false based on success
}
};
To copy to clipboard, switch view to plain text mode
You then use this roughly as follows:
// When point type is first determined
pt_t_builder * ptBuilder = 0;
pt_t_parser * ptParser = 0;
switch( fileType )
{
case pt1_t_file:
{
ptBuilder = new pt1_t_builder;
ptParser = new pt1_t_parser;
}
break;
// .. additional cases for other point types
}
// Later, when reading each line:
std::wstring line; // read the line into "line"
ptcore_t * point = (*ptBuilder)(); // create the appropriate point type based on the builder
if ( (*ptParser)( point, line ) ) // load the new point's contents based on the parser and store if OK
myVector[ nPoint++ ] = point;
// When point type is first determined
pt_t_builder * ptBuilder = 0;
pt_t_parser * ptParser = 0;
switch( fileType )
{
case pt1_t_file:
{
ptBuilder = new pt1_t_builder;
ptParser = new pt1_t_parser;
}
break;
// .. additional cases for other point types
}
// Later, when reading each line:
std::wstring line; // read the line into "line"
ptcore_t * point = (*ptBuilder)(); // create the appropriate point type based on the builder
if ( (*ptParser)( point, line ) ) // load the new point's contents based on the parser and store if OK
myVector[ nPoint++ ] = point;
To copy to clipboard, switch view to plain text mode
HTH. Obviously not compiled or tested, so some tweaking might be required.
Bookmarks