473,407 Members | 2,312 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,407 software developers and data experts.

Generic Memory Pointers/Access

Hi Everyone,

I have a design-/implementation-related question for you all.

In practical usage of C++, especially when processing image or audio data
with 3rd party libraries, there often arises the situation in which a memory
location has to be interpreted as a collection of values of a specific data
type. For example, imagine an audio API that returns void* in a request to
GetSamples(). A simple loop outputting each sample may be:

if (BytesPerSample == 1)
{
// Single byte case (1 - 8 bits per sample)
ty1ByteType* pAudioBuffer =
reinterpret_cast<ty1ByteType*>(AudioData.GetSample s());

for (int SampleNo = 0; SampleNo < NumberOfSamples; SampleNo++)
{
cout << SampleNo << ": " << *(pAudioBuffer++) << endl;
}
}
else if (BytesPerSample == 2)
{
// Double byte case (9 - 16 bits per sample)
ty2ByteType* pAudioBuffer =
reinterpret_cast<ty2ByteType*>(AudioData.GetSample s());

for (int SampleNo = 0; SampleNo < NumberOfSamples; SampleNo++)
{
cout << SampleNo << ": " << *(pAudioBuffer++) << endl;
}
}
else
{
throw ... // Unsupported byte depth
}

Obviously the repeated code is thoroughly undesirable. The code could be
modified so that the processing loop occurs on the outside and the pointer
is cast at each iteration, but this isn't desirable either. As further
depths are supported, the problem snowballs.

I am wondering how other people have addressed this oft occurring problem. I
would like to write the processing code only once and, preferably,
initialise the pointer once also. Initially I thought of writing a
template-based hierarchy, that would allow the following approach:

CMyPointer* pAudio = CMyPointer::CreateInstance(Audio.GetSamples(),
ByteDepth);
CMyPointer& pAudioBuffer = *pAudio;

for (int SampleNo = 0; ...)
{
cout << ... << *(pAudioBuffer++) ...
}

delete pAudio;

To do this, CMyPointer would need to be an abstract non-template-based class
presenting the 'named constructor' CreateInstance and pure virtual pointer
functions. CreateInstance would return the correct typed instance of the
subclass CMyTypedPointer<DATA_TYPE> pointing to the given address using a
datatype of the appropriate byte depth. The problem here arises when
considering the operator*() function in the base class - because this is not
a template-based class, a specific return type has be given which would
differ in instances of the base classes.

What solutions to this scenario have people employed? Of course, it would be
further preferable to cast the memory to any arbitrary type, including
objects.

Many thanks.
Lucy x
Jul 22 '05 #1
2 1397
What solutions to this scenario have people employed? Of course, it would be
further preferable to cast the memory to any arbitrary type, including
objects.

I'm not that familiar with your problem, as I don't use pointer classes
in general. However, I tend to solve similar problems this way:

template <int size, class type>
SomeFunctionheader(...)//insert neccessary parameters here
{
type* pAudioBuffer = reinterpret_cast<type*>(AudioData.GetSamples());

for (int SampleNo = 0; SampleNo < NumberOfSamples; SampleNo++)
{
cout << SampleNo << ": " << *(pAudioBuffer++) << endl;
}
}

//...

if (BytesPerSample == 1)
{
SomeFunction<1,ty1ByteType>(...);
}
else if (BytesPerSample == 2)
{
SomeFunction<2,ty2ByteType>(...);
}
else
{
throw ... // Unsupported byte depth
}

The resulting executable should be almost equivalent.

Hope that helps,
Bernd Fuhrmann
Jul 22 '05 #2
"Patchwork" <ID***********@IDontLike.Spam> wrote in message
news:bs**********@sparta.btinternet.com...
Hi Everyone,

I have a design-/implementation-related question for you all.

In practical usage of C++, especially when processing image or audio data
with 3rd party libraries, there often arises the situation in which a memory location has to be interpreted as a collection of values of a specific data type. For example, imagine an audio API that returns void* in a request to
GetSamples(). A simple loop outputting each sample may be:

if (BytesPerSample == 1)
{
// Single byte case (1 - 8 bits per sample)
ty1ByteType* pAudioBuffer =
reinterpret_cast<ty1ByteType*>(AudioData.GetSample s());

for (int SampleNo = 0; SampleNo < NumberOfSamples; SampleNo++)
{
cout << SampleNo << ": " << *(pAudioBuffer++) << endl;
}
}
else if (BytesPerSample == 2)
{
// Double byte case (9 - 16 bits per sample)
ty2ByteType* pAudioBuffer =
reinterpret_cast<ty2ByteType*>(AudioData.GetSample s());

for (int SampleNo = 0; SampleNo < NumberOfSamples; SampleNo++)
{
cout << SampleNo << ": " << *(pAudioBuffer++) << endl;
}
}
else
{
throw ... // Unsupported byte depth
}

Obviously the repeated code is thoroughly undesirable. The code could be
modified so that the processing loop occurs on the outside and the pointer
is cast at each iteration, but this isn't desirable either. As further
depths are supported, the problem snowballs.

I am wondering how other people have addressed this oft occurring problem. I would like to write the processing code only once and, preferably,
initialise the pointer once also. Initially I thought of writing a
template-based hierarchy, that would allow the following approach:

CMyPointer* pAudio = CMyPointer::CreateInstance(Audio.GetSamples(),
ByteDepth);
CMyPointer& pAudioBuffer = *pAudio;

for (int SampleNo = 0; ...)
{
cout << ... << *(pAudioBuffer++) ...
}

delete pAudio;

To do this, CMyPointer would need to be an abstract non-template-based class presenting the 'named constructor' CreateInstance and pure virtual pointer
functions. CreateInstance would return the correct typed instance of the
subclass CMyTypedPointer<DATA_TYPE> pointing to the given address using a
datatype of the appropriate byte depth. The problem here arises when
considering the operator*() function in the base class - because this is not a template-based class, a specific return type has be given which would
differ in instances of the base classes.

What solutions to this scenario have people employed? Of course, it would be further preferable to cast the memory to any arbitrary type, including
objects.

Many thanks.
Lucy x


First of all, try to refrain from using reinterpret_cast -- it is the most
dangerous of the C++ cast types. A static_cast should be enough to convert a
void pointer.

Next, isolate the casting to a couple of functions:

ty1ByteType *ty1(AudioDataType &AudioData)
{
if (AudioData.BytesPerSample != 1)
throw a_fit();
return static_cast<ty1ByteType*>(AudioData.GetSamples());
}

ty2ByteType *ty2(AudioDataType &AudioData)
{
if (AudioData.BytesPerSample != 2)
throw a_fit();
return static_cast<ty2ByteType*>(AudioData.GetSamples());
}

I assumed that the bytes per sample was available from AudioData's type. I
sure hope so, because not checking here would be a big mistake. It would be
far too easy to type ty2 when you meant ty1 and get the wrong cast.

Then write your processing code template style:

template <typename BYTETYPE> // BYTETYPE is ty1ByteType or ty2ByteType
display_audio(BYTETYPE *ptr, int NumberOfSamples)
{
for (int SampleNo = 0; SampleNo < NumberOfSamples; SampleNo++)
cout << SampleNo << ": " << *(ptr++) << endl;
}

You might call this function using another function as follows:

display_audio(AudioDataType &AudioData)
{
if (AudioData.BytesPerSample == 1)
display_audio(ty1(AudioData), NumberOfSamples);
else if (AudioData.BytesPerSample == 2)
display_audio(ty2(AudioData), NumberOfSamples);
else
bomb_city();
}

It still isn't the prettiest thing in the world, but when dealing with
legacy libraries you do what ya gotta do. If you look at the gamut of
operations you want to do with your audio data you can probably write a very
clean wrapper that hides these ugly details, perhaps using polymorphism to
avoid the if/then/else ladders. Then test, test, and test some more. Good
luck.

Warning: untested code above. And I make LOTS of mistakes. :)

--
Cy
http://home.rochester.rr.com/cyhome/
Jul 22 '05 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: mosfets | last post by:
Hi, I'm having a little trouble figuring out the difference in terms of memory allocation between: class person_info; class A { private:
30
by: jimjim | last post by:
Hello, This is a simple question for you all, I guess . int main(){ double *g= new double; *g = 9; delete g; cout<< sizeof(g)<<" "<<sizeof(double)<<" "<<sizeof(*g)<<" "<<*g<<" "<<endl; *g =...
11
by: Eric A. Johnson | last post by:
Hi, The book I am studying from, which comes from 1994, makes mention of far memory (i.e., that memory beyond 64K). I am under the belief, however, that far memory no longer needs any special...
10
by: s.subbarayan | last post by:
Dear all, I happen to come across this exciting inspiring article regarding memory leaks in this website: http://www.embedded.com/story/OEG20020222S0026 In this article the author mentions:...
8
by: Cool Guy | last post by:
From <http://msdn2.microsoft.com/en-us/library/f4a6ta2h(en-US,VS.80).aspx>: | As with the previous use of the Stack<T> class created with the Order | type, another instance of the specialized...
1
by: Albert | last post by:
Hello all, I've got several questions and I'm sure you'll find them easy to answer, but sadly I don't know the answers though: What do people mean by generic pointers Why is a pointer to void...
9
by: Roshni | last post by:
Hi, I wanted to know how do function pointers sometime access illegal memory access ? Could any one give me an example ? Thanks, Roshni
8
by: nkrisraj | last post by:
Hi, I have a following structure: typedef struct { RateData rdr; int RateID; char RateBalance; } RateInfo;
11
by: redefined.horizons | last post by:
First, I would thank all of those that took the time to answer my question about creating an array based on a numeric value stored in a variable. I realize after reading the responses and doing...
6
by: nmehring | last post by:
I have an MFC app with 2000 users. I have one user that experiences a crash in our software anywhere from 1 to 5 times a week when opening a particular module. No other users have reported this...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.