Classes with pointers and binary files - c++

Well guys/girls, I already asked this but I think I didn't explain good and I couldn't find the solution so I'll ask again with more details and explain more the context of my problem.
I have two classes that contain user data and I want to save them in binary files. On the other hand, I have a template class responsible for save these classes.
There is a really important fact that I have to mention: in the beginning I chose encode a auxiliary class for any class that I would save. This auxiliary class is responsible of writing/reading of data. The original classes have string members and the auxiliary classes have pointers to char. But recently, looking for more simplicity and flexibility, I chose to combine the original class, that contains the benefits of string class ;and its auxiliary that has the pointers that makes the class more comfortable at the moment of save it. So, instead of have two classes, I have one class that handles the input/output of data and the write/read of data.
This change looks something like this:
class AuxNOTE;
//Original Class: Input/Output of Data
class NOTE{
private:
string _Category;
string _Description;
public:
NOTE() : _Category( "" ) , _Description( "" ) { }
NOTE( const NOTE & note ) : _Category( note._Category )
, _Description( note._Description ) { }
NOTE( string category , string description ) : _Category( category)
, _Description( description ) { }
NOTE( const AuxNOTE & aux ) : _Category( aux._Category )
, _Description( aux._Description ) { }
NOTE & operator=( const NOTE & note ){
_Category = note._Category;
_Description = note._Description;
return *this;
}
NOTE & operator=( const AuxNOTE & aux ){
_Category = string( aux._Category );
_Description = string( aux._Description );
return *this;
}
string GetCategory() const { return _Category; }
string GetDescription() const { return _Description; }
void SetCategory( string category ) { _Category = category; }
void SetDescription( string description ) { _Description = description; }
};
//Auxliary Class: Writing/Reading of Data to/from binary files
class AuxNOTE{
private:
char _Category[50];
char _Description[255];
public:
AuxNOTE(){ }
AuxNOTE( const NOTE & note ){
strcpy( _Category , note._Category );
strcpy( _Description , note._Description);
}
AuxNOTE & operator=( const NOTE & note ){
strcpy( _Category , note._Category );
strcpy( _Description , note._Description );
return *this;
}
};
What I have now is something like this:
//Class NOTE: Input/Output of Data and Writing/Reading to/from binary files.
// .h file
class NOTE{
private:
char * _Category;
char * _Description;
public:
NOTE();
NOTE( const NOTE & note );
NOTE( string category , string description );
NOTE & operator=( const NOTE & note )
string GetCategory() const;
string GetDescription() const;
void SetCategory( string category );
void SetDescription( string description );
};
// .cpp file
#include "NOTE.h"
NOTE :: NOTE() : _Category( nullptr ) ,_Description( nullptr )
{
}
NOTE :: NOTE( string description , string category )
: _Category ( new char[ category.size() + 1 ] )
, _Categoria( new char[ description.size() + 1 ] )
{
strcpy( _Categoria , category.c_str() );
strcpy( _Descripcion , description.c_str() );
}
NOTE :: NOTE (const NOTE & copy )
: _Category( nullptr )
, _Description nullptr )
{
if( copy._Description != nullptr ){
_Description = new char[ strlen( copy._Description ) + 1 ];
strcpy( _Description , copy._Description );
}
if( copy._Category != nullptr ){
_Category = new char[ strlen( copy._Category ) + 1 ];
strcpy( _Category , copy._Category );
}
}
NOTE :: ~NOTE() {
if( _Description != nullptr ) delete [] _Description;
if( _Category != nullptr ) delete [] _Category;
}
//Get Methods
string NOTE :: GetDescription() const { return string(_Description); }
string NOTE :: GetCategory() const { return string(_Category); }
//Set Methods
void NOTE :: SetDescription( string description ){
if( _Description != nullptr ) delete [] _Description;
_Description = new char[ description.size() + 1 ];
strcpy( _Description , description.c_str() );
}
void NOTE :: SetCategory( string category ){
if( m_Category != nullptr ) delete [] _Category;
_Category = new char[ category.size() + 1 ];
strcpy( _Category , category.c_str() );
}
//Operators
NOTE & NOTE :: operator=( const NOTE & note ){
if( note._Description != nullptr ) SetDescription( note.GetDescription() );
if( note._Category != nullptr ) SetCategory( note.GetCategory() );
return *this;
}
Note that the public interface looks like if the NOTE class works with string members but it doesn't because it works with pointers to char. Thus the NOTE class can be saved without any problem. However, the class is not responsible at all of writing/reading but I created another class that can save any class as long as these classes have members that can be saved.
And the class that is responsible of this is a template class and looks like this:
template< class T >
class SAVER{
private:
vector< T > _Vector;
string _File;
public:
SAVER( string file );
~SAVER();
};
template< class T >
SAVER< T > :: SAVER( string file ) : _File( file ){
assert( _File != "" );
ifstream file( _File , ios::binary );
if( file.is_open() ){
T obj;
while( file.read( reinterpret_cast<char*>(&obj) , sizeof(obj) ) )
_Vector.push_back( obj );
}
}
template< class T >
Saver< T > :: ~Saver() {
if( _Vector.empty() )
return;
ofstream file( _File , ios::binary | ios::trunc );
assert( file.is_open() );
auto itr = _Vector.begin();
auto end = _Vector.end();
while( itr != end ){
if ( !file.write( reinterpret_cast<char*>( &itr ) , sizeof(itr) ) )
break;
itr++;
}
}
The SAVER's constructor handles the reading and puts the data( e.g NOTE objects ) in its vector. The destroyer handles the writing of all vector's objects into the corresponding binary file.
I got to clear that my errors aren't compile error but they are runtime errors.
Now, This is the problem I have:
When I execute the entire program, it has to read the binary file but it breaks. I open it with the debugger and I see that the program finishes in this line with a "segmentation fault error" and this comes from the SAVER constructor:
NOTE :: ~NOTE() {
if( _Description != nullptr ) delete [] _Description; //It breaks at this line
if( _Category != nullptr ) delete [] _Category;
}
In the debugger I can see the value of _Description and next to it appears an memory error that says: error: Cannot access memory at address (value of _Description).
Why is this happen? Do you see any error? If you need more information or you don't understand something just let me know.

First, search the internet for "c++ serialization library". What you are performing is called serialization.
Pointers and any class that contains pointers cannot be written verbatim to a file. The pointers are locations in memory. There is no guarantee by most Operating Systems that your program will have the exact memory locations next time it is executed. Your program may run in different areas of memory which change where your data is stored.
There are techniques around this, such as either writing the quantity first, then the data or writing the data then some kind of sentinel (such as the '\0' in C-Style strings).
Consider not writing as a binary file, but using formatted textual representations. A number will be read in by many platforms and converted to native representations. A native representation written in binary mode to a file, many not be the same on another platform (look up "Endianess"). Also, most text editors and word processors can easily read text files. Reading and interpreting a binary file is more difficult.
Unless your application's bottleneck is I/O bound and the I/O timing is critical, consider using textual representation of data. It is easier to read (especially when debugging your program) and easily portable.

In the debugger I can see the value of _Description and next to it appears an memory error that says: error: Cannot access memory at address (value of _Description).
Sure, you cannot deserialize pointers from your binary. You need to store their size information and contents in the file instead.

Related

How to manage memory while reading CSV using Apache Arrow C++ API?

I don't understand memory management in C++ Arrow API. I use Arrow 1.0.0 and I'm reading CSV file. After a few runs of ReadArrowTableFromCSV, my memory is full of allocated data. Am I missing something? How can I free that memory? I don't see any method in memory pool to clear all allocated memory. Code Listing below.
void LoadCSVData::ReadArrowTableFromCSV( const std::string & filePath )
{
auto tableReader = CreateTableReader( filePath );
ReadArrowTableUsingReader( *tableReader );
}
std::shared_ptr<arrow::csv::TableReader> LoadCSVData::CreateTableReader( const std::string & filePath )
{
arrow::MemoryPool* pool = arrow::default_memory_pool();
auto tableReader = arrow::csv::TableReader::Make( pool, OpenCSVFile( filePath ),
*PrepareReadOptions(), *PrepareParseOptions(), *PrepareConvertOptions() );
if ( !tableReader.ok() )
{
throw BadParametersException( std::string( "CSV file reader error: " ) + tableReader.status().ToString() );
}
return *tableReader;
}
void LoadCSVData::ReadArrowTableUsingReader( arrow::csv::TableReader & reader )
{
auto table = reader.Read();
if ( !table.ok() )
{
throw BadParametersException( std::string( "CSV file reader error: " ) + table.status().ToString() );
}
this->mArrowTable = *table;
}
std::unique_ptr<arrow::csv::ParseOptions> LoadCSVData::PrepareParseOptions()
{
auto parseOptions = std::make_unique<arrow::csv::ParseOptions>( arrow::csv::ParseOptions::Defaults() );
parseOptions->delimiter = mDelimiter;
return parseOptions;
}
std::unique_ptr<arrow::csv::ReadOptions> LoadCSVData::PrepareReadOptions()
{
auto readOptions = std::make_unique<arrow::csv::ReadOptions>( arrow::csv::ReadOptions::Defaults() );
readOptions->skip_rows = mNumberOfHeaderRows;
readOptions->block_size = 1 << 27; // 128 MB
readOptions->column_names.reserve( mTable->GetNumberOfColumns() );
for ( auto & colName : mTable->GetColumnsOrder() )
{
readOptions->column_names.emplace_back( colName );
}
return readOptions;
}
std::unique_ptr<arrow::csv::ConvertOptions> LoadCSVData::PrepareConvertOptions() const
{
auto convertOptions = std::make_unique<arrow::csv::ConvertOptions>( arrow::csv::ConvertOptions::Defaults() );
for ( auto & col : mTable->GetColumsInfo() )
{
convertOptions->column_types[col.second.GetName()] = MyTypeToArrowDataType( col.second.GetType() );
}
convertOptions->strings_can_be_null = true;
return convertOptions;
}
std::shared_ptr<arrow::io::ReadableFile> LoadCSVData::OpenCSVFile( const std::string & filePath )
{
MTR_SCOPE_FUNC();
auto inputFileResult = arrow::io::ReadableFile::Open( filePath );
if ( !inputFileResult.ok() )
{
throw BadParametersException( std::string( "CSV file reader error: " ) + inputFileResult.status().ToString() );
}
return *inputFileResult;
}
Maciej, the method TableReader::Read should return shared_ptr<arrow::Table>. The arrow::Table itself has a number of shared pointers to structures which eventually contain the data. To free up the data you will need to make sure that the arrow::Table and any copies of it are destroyed. This should happen as soon as that shared_ptr goes out of scope. However, it appears you are storing the table in a member variable here (which is to be expected, you probably want to use the data after you read it):
this->mArrowTable = *table;
So now you have a second copy of the arrow::Table instance. You could reassign this->mArrowTable to a new blank table or you could destroy whatever this is. Of course, if you are making any other copies of the table then you will need to ensure those go out of scope as well.

C++ iterator class causes R6025 run-time error in Visual C++

I have the following code, when I run the code below I get 'R6025 run-time error in Visual C++'
CommandParameterAndValue param( "Key", "value" );
parameters.AddParameter( &param );
parameters.HasParameter( "akeyval" );
I am lost, any ideas? Is it something to do with the casting?
typedef std::vector<iCommandParameter *> ParamsVectorList;
class CommandParametersList
{
public:
.... functions here ....
void AddParameter( iCommandParameter *param );
bool HasParameter( std::string parameterKey );
protected:
ParamsVectorList m_parameters;
};
void CommandParametersList::AddParameter( iCommandParameter *param )
{
m_parameters.push_back( param );
}
bool CommandParametersList::HasParameter( std::string parameterKey )
{
ParamsVectorList::iterator it;
CommandParameterAndValue *paramItem = NULL;
bool returnValue = false;
for ( it = m_parameters.begin(); it != m_parameters.end(); it++ )
{
paramItem = static_cast<CommandParameterAndValue *>( *it );
if ( paramItem->GetKey().compare( parameterKey ) == 0 )
{
returnValue = true;
break;
}
}
return returnValue;
}
I need more information to give a complete answer, but if you look here: http://support.microsoft.com/kb/125749
That run-time error means you tried to call a pure virtual function - it couldn't find an implementation. I would suggest running through a debugger and finding which line of code throws this error. Than it should be easy to understand and fix. It's probably happening here:
if ( paramItem->GetKey().compare( parameterKey ) == 0 )

Vector with custom objects: crash when I want to use one received with .at method

I have a class named CConfig, I'm creating new object:
std::vector< CConfig > docs;
CConfig newfile( "somefile.xml", "root" );
printf("%s", newfile.GetTagValue( "servername" )); // this works
docs.push_back( newfile );
When I'm getting this object with .at method
CConfig file = docs.at(0);
printf("%s", file.GetTagValue( "servername" )); // this crashes
Where's the problem?
(im sorry if formatting is wrong but currently I don't use javascript because my bandwidth is ended and max speed is 1kb/s so I'll try to fix it later)
CConfig.h:
class CConfig
{
TiXmlDocument m_doc;
TiXmlElement* m_pRoot;
bool m_bIsLoaded;
public:
CConfig ( void ) {};
CConfig ( const char * pszFileName, const char * pszRootName );
~CConfig ( void ) {};
const char* GetTagValue ( const char * pszTagName );
const char* GetTagAttribute ( const char * pszTagName, const char * pszAttributeName );
TiXmlElement* GetRootElement ( void ) { return m_pRoot; };
bool IsAvailable ( void ) { return m_bIsLoaded; };
};
CConfig.cpp
#include "CConfig.h"
CConfig::CConfig( const char * pszFileName, const char * pszRootName )
{
m_bIsLoaded = m_doc.LoadFile( pszFileName );
if( m_bIsLoaded )
m_pRoot = m_doc.FirstChildElement( pszRootName );
}
const char * CConfig::GetTagValue( const char * pszTagName )
{
if( m_bIsLoaded && m_pRoot )
{
TiXmlElement * element = m_pRoot->FirstChildElement( pszTagName );
if( element )
return element->GetText();
}
}
const char * CConfig::GetTagAttribute( const char * pszTagName, const char * pszAttributeName )
{
if( m_bIsLoaded && m_pRoot )
{
TiXmlElement * element = m_pRoot->FirstChildElement( pszTagName );
if( element )
return element->Attribute( pszAttributeName );
}
}
I'm using tinyxml
Your issue is with pointers to old memory. When you add an item to an array, it is copied. Later you leave that scope and the original is destroyed, but ask yourself where the pointer in your copy is pointing? Still to the first (now deleted) object's memory. Uh-oh.
The simplest fix (while avoiding large copy operations) is to make m_doc into a shared pointer (available in the standard in C++11, or via Boost in C++03). That will then handle everything for you rule-of-3 wise. And because the underlying memory won't move, m_pRoot will remain valid until the last copy has been deleted.
If copy-space is not an issue, then fix your Rule of Three violation by properly adding a copy constructor:
CConfig(const CConfig& obj)
: m_doc(obj.m_doc)
, m_bLoaded(obj.m_bLoaded)
, m_pRoot()
{
if (m_bLoaded)
m_pRoot = m_doc.GetRootElement();
}
An assignment operator is also likely in order, but if you don't need it, hide it by declaring it (but not implementing it) as private or use the C++11 delete attribute feature.
Interestingly enough, you don't even need the m_bLoaded member. A non-NULL root pointer can indicate your loaded-state, but that is a separate issue. This at least be enough to get you up and running.

C++ Prepend DateTime to console output

Searched around and couldn't find any info on this besides redirecting to files so hopefully someone can help me out.
I have a console application that launches and hooks another process, by default the new process output displays in the first console application.
What I would like to do is prepend a datetime value to all the output, the problem is that I don't control the output from the child process (3rd party app) so the easy solution of adding a datetime to all printed values is unavailable. Is it possible to prepend a string to all stdout?
Since you confirmed C++ (which implies a solution for
std::cout is what is needed, and not for stdout): the
obvious solution is a filtering streambuf:
class TimeStampStreambuf : public std::streambuf
{
std::streambuf* myDest;
std::ostream* myOwner;
bool myIsAtStartOfLine;
protected:
int overflow( int ch )
{
// To allow truly empty lines, otherwise drop the
// first condition...
if ( ch != '\n' && myIsAtStartOfLine ) {
std::string tmp = now();
// function now() should return the timestamp as a string
myDest->sputn( tmp.data(), tmp.size() );
}
myIsAtStartOfLine = ch == '\n';
ch = myDest->sputc( ch );
return ch;
}
public:
TimeStampStreambuf( std::streambuf* dest )
: myDest( dest )
, myOwner( nullptr )
, myIsAtStartOfLine( false )
{
}
TimeStampStreambuf( std::ostream& owner )
: myDest( dest.rdbuf() )
, myOwner( &owner )
, myIsAtStartOfLine( false )
{
myOwner->rdbuf( this );
}
~TimeStampStreambuf()
{
if ( myOwner != nullptr ) {
myOwner->rdbuf( myDest );
}
}
};
And to install it:
// scoped:
TimeStampStreambuf anyName( std::cout );
// Time stamping will be turned off when variable goes out
// of scope.
// unscoped:
std::streambuf* savedStreambuf = std::cout.rdbuf();
TimeStampStreambuf name( savedStreambuf );
// In this case, you have to restore the original streambuf
// yourself before calling exit.
As far as I know, the articles explaining this (from C++
Reports, Sept. 1998) are not on line.
EDIT:
I've actually found them:
http://gabisoft.free.fr/articles-en.html. I can't believe that
the link still works; it's been years since I had an account
with Free.

C++ runtime field access

class SuperClass{
/* ==================== METHODS ======================================= */
void
setValue (
std::string name,
int i ) {
MemberMapIterator it = memberMap_.find ( name );
if ( it != memberMap_.end ( ) ) {
void* ptr = ( *it ).second;
long long classPtr = reinterpret_cast< long long > ( this );
long long memberPtr = reinterpret_cast< long long > ( ptr );
int* value = reinterpret_cast< int* > ( classPtr + memberPtr );
( *value ) = i;
}
} // setValue
int
getValue (
std::string name ) {
MemberMapIterator it = memberMap_.find ( name );
if ( it != memberMap_.end ( ) ) {
void* ptr = ( *it ).second;
long long classPtr = reinterpret_cast< long long > ( this );
long long memberPtr = reinterpret_cast< long long > ( ptr );
int* value = reinterpret_cast< int* > ( classPtr + memberPtr );
return *value;
}
return -234234;
} // getValue
protected:
/* ==================== METHODS ======================================= */
void
Build ( ) {
configure ( );
} // Build
void
AddMember (
std::string name,
void* ptr ) {
memberMap_.insert ( MemberMapPair ( name, ptr ) );
} // AddMember
/* ==================== STATIC METHODS======================================= */
virtual void
configure ( ) = 0;
private:
/* ==================== METHODS ======================================= */
/* ==================== DATA MEMBERS ======================================= */
MemberMap memberMap_;
};
class SubClass: public SuperClass {
public:
/* ==================== LIFECYCLE ======================================= */
SubClass( ) : age_ ( 0 ) {
Build ( );
} /* constructor */
~SubClass( ) /* destructor */
{ }
protected:
/* ==================== STATIC METHODS======================================= */
void
configure ( ) {
long long classPtr = reinterpret_cast< long long > ( this );
long long agePtr = reinterpret_cast< long long > ( &this->age_ );
void* ptr = reinterpret_cast< void* > ( agePtr - classPtr );
this->AddMember ( "age", ptr );
} // configure
private:
/* ==================== DATA MEMBERS ======================================= */
int age_;
}
In SubClass, I add the offset of the private class field (thinking about the class as a C structure) the Super class map using string name as a key.I will make to execute configure only once and then I want to use this offset for every Person instance to access to its private fields at runtime (this + offset = field). Will be this safe? I tested this code and its work it is doing what I want. But should I expect any memory violations or something else (assuming that it won't be intentional violation (programmer errors))?
First of all, it's worth knowing that C++ classes are not like C structs. The compiler puts extra things in classes like the vtable pointer, which could be in the beginning, the end, or somewhere else depending on the compiler. There is one kind of class that behaves like a C struct (i.e. a bag of bits) and they're called Plain Old Data types (POD). You can find plenty on them on StackOverflow. Since you're using inheritance, you're not using a POD.
If you're trying to forcefully access private members, you probably need to rework your design. You should ask yourself why they're private in the first place. Based on what it looks like you're going for in the code, I can think of more straightforward approaches:
Cast the base class to the subclass, then set the private member with a setter function.
You could make setValue and getValue virtual and override it in the subclass.
Use friendship.