implementation details

F

forums_mp

After reading a few texts - nameley koeing/moo and eckel - I decided
to investigating the importance of templates. Of course there's no
substitute for practice so I figured I try a simple program.

That said I'm interested in suggestions for improvement on the
template class (be gracious i'm slowly coming up to speed in ++ :))
but more importantly I have a few questions.
For starters, in an ideal world each call to Store should be followed
by a subsequent Retrieve. If however, Store was called twice before a
Retrieve then I'd like to implement some sort of overrun check. I
suspect this could be handled with an overrun_count that'll get
incremented in Store and decremented in Retrieve or (implementation
help here)???

Conceptually I understand teh copy constructor and/or assignment
operator (the heavy stuff but need to revisit) but I'm curious to see
an implementation of the assignment operator that'll compare two
buffers and a copy constructor that'll do just that. Copy an new
object based on exisitng.

The code


// template.h
enum BOOLEAN { FALSE = 0,
TRUE};

template <class T>
class BUFFER
{
public:

BUFFER();
~BUFFER();
void Store(unsigned char const* buffer);
BOOLEAN Retrieve(T& data);
// T Retrieve(T& data); would this be more prudent ??
int Elements_Stored() const;
int Elements_Retrieved() const;

private:

static const int SIZE = 2;
T msg [ SIZE ];

unsigned int store_count;
unsigned int store_index;
unsigned int retrieve_count;

// override compiler defaults
BUFFER(BUFFER<T>& buffer); // Copy construtor.
void operator= (BUFFER<T>& rhs); // Assignment operator


};

// Constructor
template<class T>
BUFFER<T>::BUFFER()
: store_count(0), retrieve_count(0), store_index(1)
{
memset( msg, 0, SIZE * sizeof(T));
}

// Destructor
template<class T>
BUFFER<T>::~BUFFER()
{
}

// store two items. the current and the previous
template<class T>
void BUFFER<T>::Store( unsigned char const* buffer)
{
store_index ^= 1;
// supposidely memcpy is bad news but std::copy benchmarked is slow
// when compared to memcpy
memcpy( &msg[store_index], buffer, sizeof(T));
store_count++; // increment the message stored count
}

// retrieve the most CURRENT item at ALL times
template<class T>
BOOLEAN BUFFER<T>::Retrieve(T& data)
{
if (store_count > 0) // here only to ensure the Retrieve never
// gets called the VERY FIRST TIME before the
Store
{
memcpy( &data, &msg[store_index], sizeof(T));
retrieve_count++;
return TRUE;
}
else
{
return FALSE;
}
}

// returns number of elements stored.
template<class T>
int BUFFER<T>::Elements_Stored() const
{
return store_count;
}

// returns number of elements retrieved.
template<class T>
int BUFFER<T>::Elements_Retrieved() const
{
return retrieve_count;
}


// template.cpp file

#define MAX_MSG_SIZE 4 // avoid preprocessor macro in a ++
environment

enum BOGUS_MSG { msg1Msg,
msg2Msg };

// For simplicity make bit fields 8 deep
struct MSG1
{
unsigned int jdx1 : 8;
unsigned int jdx2 : 8;
unsigned int jdx3 : 8;
unsigned int jdx4 : 8;
};

struct MSG2
{
unsigned int idx1 : 8;
unsigned int idx2 : 8;
unsigned int idx3 : 8;
unsigned int idx4 : 8;
};


int main ( void )
{

BOGUS_MSG msgType;
MSG1 localMsg;
BOOLEAN success;

// Done once at initilization.
BUFFER<MSG1> msg1;
BUFFER<MSG2> msg2;

unsigned char buffer [ MAX_MSG_SIZE ] = { 12, 1, 15, 5 };
memset(&localMsg, 0, sizeof(MSG1)); // no real reason since
// I'll overwrite
localMsg

std::cout << " ----- Before call to Store and Retrieve ---- "
<< std::endl;
std::cout << "MSG1 - jdx1 = " << localMsg.jdx1 << std::endl;
std::cout << "MSG1 - jdx2 = "<< localMsg.jdx2 << std::endl;
std::cout << "MSG1 - jdx3 = " << localMsg.jdx3 << std::endl;
std::cout << "MSG1 - jdx4 = " << localMsg.jdx4 << std::endl;

msgType = msg1Msg;

switch ( msgType )
{
case msg1Msg:
msg1.Store ( buffer );
break;
case msg2Msg:
msg2.Store ( buffer );
break;
default:
std::cout << " bad msg " << std::endl;
break;
}

// later lets Retrieve a message
success = msg1.Retrieve(localMsg); // retrieve the message
if ( success )
{
std::cout << " ----- After call to Store and Retrieve ---- "
<< std::endl;
std::cout << "MSG1 - jdx1 = " << localMsg.jdx1 << std::endl;
std::cout << "MSG1 - jdx2 = "<< localMsg.jdx2 << std::endl;
std::cout << "MSG1 - jdx3 = " << localMsg.jdx3 << std::endl;
std::cout << "MSG1 - jdx4 = " << localMsg.jdx4 << std::endl;
}

// Call msg1.Store message a couple times
// Call msg2.Store
msg1.Store ( buffer );
msg1.Store ( buffer );
msg2.Store ( buffer );

// Print out the index of how many times msg1(should equate to 3)
stored
// Print out the index of how many times msg1(should equate to 1)
stored
std::cout << " --------------------------------------------- "
<< std::endl;
std::cout << "Times called -- MSG1: "
<< msg1.Elements_Stored()
<< std::endl;

std::cout << " --------------------------------------------- "
<< std::endl;
std::cout << "Times called -- MSG2: "
<< msg2.Elements_Stored()
<< std::endl;
std::cout << " --------------------------------------------- "
<< std::endl;

return EXIT_SUCCESS;
}//// end


I'll modify said code to move into the container realm later.

Thanks in advance
 
D

Davlet Panech

forums_mp said:
After reading a few texts - nameley koeing/moo and eckel - I decided
to investigating the importance of templates. Of course there's no
substitute for practice so I figured I try a simple program.

That said I'm interested in suggestions for improvement on the
template class (be gracious i'm slowly coming up to speed in ++ :))
but more importantly I have a few questions.
For starters, in an ideal world each call to Store should be followed
by a subsequent Retrieve. If however, Store was called twice before a
Retrieve then I'd like to implement some sort of overrun check. I
suspect this could be handled with an overrun_count that'll get
incremented in Store and decremented in Retrieve or (implementation
help here)???

Conceptually I understand teh copy constructor and/or assignment
operator (the heavy stuff but need to revisit) but I'm curious to see
an implementation of the assignment operator that'll compare two
buffers and a copy constructor that'll do just that. Copy an new
object based on exisitng.

The code

Perhaps you should state what your buffer class is supposed to do. As far as
I can tell it's trying to convert objects of arbitrary types to char arrays.
This will only work for POD types (ints, pointers, structs w/o virtual
members, constructors, etc.). Why don't you try to implement a class that
actually makes sense and is a bit more useful, like a stack of a fixed size.

Anyway, some observations:
- "template.h" is too vague a file name. ".h" is usually used with C
headers. I suggest <ClassName>.hpp instead.
- There is a perfectly good boolean type in C++ already (bool/true/false).
- Since your destructor doesn't do anything, you don't have to declare and
define it.
- Copy ctor takes its argument by *const reference*.
- Assignment operator takes its argument by *const reference* and returns a
*non-const reference" to current object ("return *this;").
- I don't think you need a copy ctor and assignment op in your class at all.
Although I'm not 100% sure as it's a little hard to understand what you are
trying to accomplish. If you don't have members that require explicit
allocation/deallocation, you usually don't need to write copy functions or
the destructor.

D.
 
F

forums_mp

Perhaps you should state what your buffer class is supposed to do. As far as
I can tell it's trying to convert objects of arbitrary types to char arrays.
This will only work for POD types (ints, pointers, structs w/o virtual
members, constructors, etc.). Why don't you try to implement a class that
actually makes sense and is a bit more useful, like a stack of a fixed size.

Makes 'sense' in what respect? In that regard I'm curious to see how
a stack of a fixed size will be oso differnt when compared to the
simple implementation which I assumed you've 'looked' at. Of course,
realize i'm new to this but in the end all i'm trying to do is
implement a store function that when called will store the most
current and previous message ( a buffer two deep). A retrieve
fucntion when called will return the latest.
Anyway, some observations:
- "template.h" is too vague a file name. ".h" is usually used with C
headers. I suggest <ClassName>.hpp instead.
I've seen this 'hpp' bit but i'll investigate what that's all about.
In essense, whats the net gain. Is this some new form of 'header'?
- There is a perfectly good boolean type in C++ already (bool/true/false).
- Since your destructor doesn't do anything, you don't have to declare and
define it. agreed on two counts.
- Copy ctor takes its argument by *const reference*. Yikes, missing the const
- Assignment operator takes its argument by *const reference* and returns a
*non-const reference" to current object ("return *this;"). ditto
- I don't think you need a copy ctor and assignment op in your class at all.
Although I'm not 100% sure as it's a little hard to understand what you are
trying to accomplish. If you don't have members that require explicit
allocation/deallocation, you usually don't need to write copy functions or
the destructor.
and I dont require explicit alloc/dealloc. got it!! in light of the
copy cstructor i thought well if I had.

BUFFER<MSG1 > b2;

// later
 
D

Davlet Panech

forums_mp said:
size.

Makes 'sense' in what respect? In that regard I'm curious to see how
a stack of a fixed size will be oso differnt when compared to the
simple implementation which I assumed you've 'looked' at. Of course,
realize i'm new to this but in the end all i'm trying to do is
implement a store function that when called will store the most
current and previous message ( a buffer two deep). A retrieve
fucntion when called will return the latest.

What I'm saying is you can't do "byte copying" (memcpy(), or equivalent)
with most classes. You should use assignment or copy constrution instead,
instead of "memcpy (&array[index], &a, sizeof (a))", do "array[index] = a".
I've seen this 'hpp' bit but i'll investigate what that's all about.
In essense, whats the net gain. Is this some new form of 'header'?

It's just a common convention; compilers don't care about file names.
and I dont require explicit alloc/dealloc. got it!! in light of the
copy cstructor i thought well if I had.

BUFFER<MSG1 > b2;

// later
BUFFER<MSG1 > b3 = b2; // cpystructor would come in handy here?

If you don't write a copy ctor/assignment, the compiler will generate one
that copies every member of the source object to the corresponding members
of the destination object. This is good enough for your case.

In other words,
BUFFER<MSG1 > b3 = b2;
will do what you expect even if you don't write copy functions yourself.

D.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top