C++ runtime field access - c++

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.

Related

Classes with pointers and binary files

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.

How do I cast a void pointer to a int[3]?

I need to call a 3rd party library and pass in an int[3] as a void * like this [works]:
int pattern[3] = {2,4,10};
if ( OSTaskCreate( BlinkLED,
( void * ) pattern,
( void * ) &BlinkTaskStack[USER_TASK_STK_SIZE],
( void * ) BlinkTaskStack,
MAIN_PRIO - 1 ) != OS_NO_ERR )
{
iprintf( "*** Error creating blink task\r\n" );
}
But now I need to parse a string to get the pattern array and I can't seem to get it right.
First I pass the string into the parser and get back the array:
int (&ParseBlinkOnCommand(char rxbuffer[3]))[3]
{
// Code parses rxbuffer and creates the 3 ints needed
int pattern[3] = {repeats, onTicks, offTicks};
return pattern;
}
Then I try to pass it to the OSTaskCreate just like I did before:
int pattern2[3] = ParseBlinkOnCommand(rxbuffer);
if ( OSTaskCreate( BlinkLED,
( void * ) pattern2,
( void * ) &BlinkTaskStack[USER_TASK_STK_SIZE],
( void * ) BlinkTaskStack,
MAIN_PRIO - 1 ) != OS_NO_ERR )
{
iprintf( "*** Error creating remote blink task\r\n" );
}
but I get the error 'array must be initialized with a brace-enclosed initializer'.
What is the right way to do this?
First, ParseBlinkOnCommand returns reference to local object and so return dangling reference.
Second C-array are not copyable, so int pattern2[3] = ParseBlinkOnCommand(rxbuffer); should be int (&pattern2)[3] = ParseBlinkOnCommand(rxbuffer);.
but why not using std::vector or std::array (or custom structure) ?
std::vector<int> ParseBlinkOnCommand(const char (&rxbuffer)[3])
{
// Code parses rxbuffer and creates the 3 ints needed
return {repeats, onTicks, offTicks};
}
And then
auto pattern2 = ParseBlinkOnCommand(rxbuffer);
if ( OSTaskCreate( BlinkLED,
pattern2.data(),
&BlinkTaskStack[USER_TASK_STK_SIZE],
BlinkTaskStack,
MAIN_PRIO - 1 ) != OS_NO_ERR )
{
iprintf( "*** Error creating remote blink task\r\n" );
}

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.

Memory Alignment issue with std::map on Linux

I have run into a problem while working with c++ over Linux.
I have a base Message class which looks like this:
class MsgBase
{
public:
MsgBase( unsigned int msgid );
map < unsigned int, MSGIEBase* > messageIE_Map; // map for IEs
unsigned int messageId; // 32 bit message id
};
class Der1 is derived from MsgBase and looks like:
class Der1 : public MsgBase
{
public:
Der1 ();
virtual ~Der1 ();
// IEs
MSGIE_UINT32 ueId;
MSGIE_String configFileName;
};
Here MSGIE_UINT32 and MSGIE_String are classes derived from MSGIEBase and therefore their address can be stored in the map defined in base class above.
When Der1 is constructed the address of ueId and configFileName is stored in the map.
Here if I print the size of map ( through gdb and in the program ) it comes to be 24.
[ _M_header = 16, _M_node_count = 4, _M_key_compare = 1, 3 byte padding I suppose ].
Till here everything is fine. Now the Der1 object pointer is put inside an event object and the event is post into a queue. The event class looks like:
class Event
{
public:
MsgBase* msgPtr;
};
A different thread removes the event from the queue, extracts the msgPtr and casts it into Der1 Pointer and this is where the problem starts.
Here if I print the size of the map in the program it is 21. That means the address of the next member in the MsgBase class i.e. messageId gets shifted by 3 bytes and so the value of messageId changes completely. (when seen through gdb, the address is still intact and so is the size of the map i.e. 24 ).
This is a word alignment issue to the best of my knowledge but why is the memory alignment not consistent in different functions and why does the address of a member of a class chage when the memory to the class has been allocated using new. I am using Linux 2.6.27. , gcc version 4.1.1. , RHEL-4.
For ruling out non-virtual destructor/copy/assignment problems, please add the following to MsgBase:
public:
virtual ~MsgBase();
private:
MsgBase(MsgBase const& other);
MsgBase& operator=(MsgBase const& other);
I will try to provide all the required information step by step:
Information 1 : The relevant code.
//Step 1: Create msg and fill message Id
MsgBase*msgPtr = new Der1();
// C'tor of Der1 is as follows:
Der1::Der1 ()
: MsgBase ( ATS_SUTD_EPCTESTER_ATTACH_SCENARIO_MsgId ), // msgid is 13( 0xd )
ueId ( IE_UE_KEY, "UE", false ),
configFileName ( IE_CONFIG_FILE_NAME_KEY, "Configuration File Name", false )
{
// Insert the IEs in the map
this->addIEEntry ( IE_UE_KEY, &ueId ); // this puts entries in the map
this->addIEEntry ( IE_CONFIG_FILE_NAME_KEY, &configFileName );
}
// Step 2: Declare event and post the event
Event* event = new Event ( eventId, "Event" );
event->setData( msgPtr, hdr);
// check the message id at this stage (
cout << "msgId = " << ( ( (Der1* )msgPtr )->messageId )<< endl; // Here it comes out
// to be 0xd which is correct
// post the event
AppClass::getInstance()->addEventAndSchedule ( event );
//The queue is a member of AppClass and has been defined as
std::list <EventBase* > eventQueue;
// The code which inserts data into the queue is as follows:
bool AppClass::addEventAndSchedule ( EventBase* ev )
{
if ( ev == NULL ) return false;
this->eventQueueMutex.acquireLock();
this->eventQueue.push_back( ev );
this->eventQueueMutex.releaseLock();
// Submit Job to Scheduler
bool status = JobScheduler::getInstance()->scheduleJob( this );
return status;
}
// The event class is
class Event: public EventBase
{
public:
Event ();
virtual ~Event ();
Event ( int evId );
Event ( int evId, string evName );
MsgBase* getMessagePtr ();
void setData ( MsgBase* mPtr, Header* hPtr )
private:
// Prevent copying
Event& operator= ( Event& ev );
Event ( Event& evBase );
MsgBase* msgPtr;
Header* hdrPtr;
};
void Event::setData ( MsgBase* mPtr, Header* hPtr )
{
this->msgPtr = mPtr;
this->hdrPtr = hPtr;
}
Step 3 : Extract the event and re-print the message Id
// The code which extracts data from the queue is as follows:
void AppClass::process ()
{
EventBase* beventPtr = NULL;
this->eventQueueMutex.acquireLock();
if ( !this->eventQueue.empty() )
{
beventPtr = (EventBase* )( this->eventQueue.front() );
this->eventQueue.pop_front();
}
else
{
isQueueEmpty = true;
}
this->eventQueueMutex.releaseLock();
Event* eventPtr = ( Event* )beventPtr ;
Der1* msgPtr = (Der1* )( eventPtr->getMessagePtr()) ;
cout << "msgId = " << msgPtr->messageId << endl; // This value
//comes out to be incorrect it is now 0xd000000 i.e. a 3 byte shift
}
Information 2 : Exact problem.
The exact problem is that the 'messasgeId' is getting changed in transition. Initially it is 0xd but after popping from the queue it becomes 0xd000000. Because of this all the processing stops. The address of this parameter also changes from 0x82bd7cc to 0x82bd7c9 when printed in the program. However when seen from gdb it is still 0x82bd7cc and the value is still 0xd.
Information 3 : Compiler Flags.
Compiler Flags are same for all the files and they are:
-O0 -g3 -Wall -fmessage-length=0