Encapsulation idiom

J

jmsantoss

Hi,

This is a design question. I have a class named "DataBuffer" that
stores some data. After "DataBuffer" is created it can not be modified.
All the methods of "DataBuffer" are const as data can not be modified
after it was created.

Up to here everything is fine. The problem is when I want to get clever
with data storage. My program has an array of "DataBuffers" that gets
pre-allocated. If I want to use that memory instead of creating a new
"DataBuffer" each time, I get a pointer to the internal data with a
method and then I use that to fill the data directly. The problem with
this is that it breaks encapsulation as everybody has now access to the
internal data.

Alternatively, I can still use the constructor option, create a new
instance of "DataBuffer" on the stack (or previsouly allocated) with
the new data and then do a copy (operator=) to the data previously
allocated. This works and doesn't break encapsulation but is rather
inefficient as it uses two copies of the data.

I though on declaring the method of the class that stores the data a
"friend" of "DataBuffer". Unfortunately, I use inheritance and a
virtual method so "friend" does not work.

Does anybody knows of a way to do this without braking encapsulation
and without paying an efficiency penalty?

Thanks
 
T

TB

(e-mail address removed) sade:
Hi,

This is a design question. I have a class named "DataBuffer" that
stores some data. After "DataBuffer" is created it can not be modified.
All the methods of "DataBuffer" are const as data can not be modified
after it was created.

Up to here everything is fine. The problem is when I want to get clever
with data storage. My program has an array of "DataBuffers" that gets
pre-allocated. If I want to use that memory instead of creating a new
"DataBuffer" each time, I get a pointer to the internal data with a
method and then I use that to fill the data directly. The problem with
this is that it breaks encapsulation as everybody has now access to the
internal data.

Alternatively, I can still use the constructor option, create a new
instance of "DataBuffer" on the stack (or previsouly allocated) with
the new data and then do a copy (operator=) to the data previously
allocated. This works and doesn't break encapsulation but is rather
inefficient as it uses two copies of the data.

I though on declaring the method of the class that stores the data a
"friend" of "DataBuffer". Unfortunately, I use inheritance and a
virtual method so "friend" does not work.

Does anybody knows of a way to do this without braking encapsulation
and without paying an efficiency penalty?

Thanks

Provide an iterator instead of a raw pointer.
 
V

Victor Bazarov

This is a design question. I have a class named "DataBuffer" that
stores some data. After "DataBuffer" is created it can not be modified.
All the methods of "DataBuffer" are const as data can not be modified
after it was created.

Up to here everything is fine. The problem is when I want to get clever
with data storage. My program has an array of "DataBuffers" that gets
pre-allocated. If I want to use that memory instead of creating a new
"DataBuffer" each time, I get a pointer to the internal data with a
method and then I use that to fill the data directly. The problem with
this is that it breaks encapsulation as everybody has now access to the
internal data.

Uh... Why do you need to "get a pointer to the internal data"? Can't you
simply use 'placement new' and _construct_ the object? Of course, you
have to remember to destroy the element once it's not needed any longer.

I would recommend to have a _factory_ for your objects that would do what
you describe. It will _own_ the array of elements and give out the stored
objects by pointer by creating another one in place. This is "pooling",
you have a "pool" of elements (or placeholders) and reuse them. Of course
the pool has to be inaccessible for anybody else but the factory.

V
 
A

Alf P. Steinbach

* (e-mail address removed):
This is a design question. I have a class named "DataBuffer" that
stores some data. After "DataBuffer" is created it can not be modified.
All the methods of "DataBuffer" are const as data can not be modified
after it was created.

Good so far, you have logically const DataBuffer obejcts.

Up to here everything is fine. The problem is when I want to get clever
with data storage.

Ah, there's the rub, yes.

General advice is, _don't_ be "clever".

But since you probably have good reasons (unstated), I'll address that
question.

My program has an array of "DataBuffers" that gets pre-allocated.

A pool.

If I want to use that memory instead of creating a new
"DataBuffer" each time, I get a pointer to the internal data with a
method and then I use that to fill the data directly. The problem with
this is that it breaks encapsulation as everybody has now access to the
internal data.

Yes, that's a problem.

It's simple.

Have a pool of storage instead of a pool of DataBuffer objects.

When constructing a DataBuffer object, obtain a pointer to storage from
the pool, and pass that to the DataBuffer constructor.

When destroying a DataBuffer object, return its data storage to the
pool.

Alternatively, I can still use the constructor option, create a new
instance of "DataBuffer" on the stack (or previsouly allocated) with
the new data and then do a copy (operator=) to the data previously
allocated. This works and doesn't break encapsulation

(1) It doesn't work because (2) it does break encapsulation (and it's
inconsistent with your earlier claim that all 'methods' are const).

If DataBuffer objects are meant to be logically const, remove access to
copy assignment.

but is rather
inefficient as it uses two copies of the data.

And yes, (3), it's inefficient in addition to being unsafe.

I though on declaring the method of the class that stores the data a
"friend" of "DataBuffer". Unfortunately, I use inheritance and a
virtual method so "friend" does not work.

To me neither of these two statements are meaningful, sorry.

Does anybody knows of a way to do this without braking encapsulation
and without paying an efficiency penalty?

See above.

Hth.,

- Alf
 
J

jmsantoss

Regarding TB's answer, I'll prefer not to have access at all so I
consider an iterator almost the same as direct memory access.

On Victor's answer, the problem that I have with "placement new" is
that "DataBuffer" is a storage class that also has containers. Actually
one of the members is a Qt's QVector. Basically I think I can't pre
allocate a memory pool and then use it as the storage for the array of
DataBuffers.

My other thought (on the factory line) is this. What if the interface
class (the base of the class that actually does the job of reading the
data and store it in a DataBuffer by a virtual method) has a non
inherited method (factory method) that is a "friend" of "DataBuffer"
and then calls the "virtual storage method" that used to have a
DataBuffer* as a parameter but now pass the internal pointer? I can do
that now that the factory is a "friend" method. I'm not sure if this is
too ugly but it doesn't seem to violate encapsulation and nobody
besides the factory method can change the data.
 
V

Victor Bazarov

Regarding TB's answer, I'll prefer not to have access at all so I
consider an iterator almost the same as direct memory access.

On Victor's answer, the problem that I have with "placement new" is
that "DataBuffer" is a storage class that also has containers.
Actually one of the members is a Qt's QVector. Basically I think I
can't pre allocate a memory pool and then use it as the storage for
the array of DataBuffers.

This is a common misconception about the size of object that
themselves have some dynamic memory allocation. I don't want to
get into it, twice a week is one time too many. If you can't
preallocate memory, don't.
My other thought (on the factory line) is this. What if the interface
class (the base of the class that actually does the job of reading the
data and store it in a DataBuffer by a virtual method) has a non
inherited method (factory method) that is a "friend" of "DataBuffer"
and then calls the "virtual storage method" that used to have a
DataBuffer* as a parameter but now pass the internal pointer?

So? Do you have a suspicion of something bad? If yes, state it.
If not, guessing game belongs to Vegas.
I can do
that now that the factory is a "friend" method. I'm not sure if this
is too ugly but it doesn't seem to violate encapsulation and nobody
besides the factory method can change the data.

If you can do it now, do it. If it does what you need, why don't
you use it already?

V
 

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

Similar Threads


Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,276
Latest member
Sawatmakal

Latest Threads

Top