Making containers that "go both ways"
Yigal Chripun
yigal100 at gmail.com
Sun Jan 27 00:01:33 PST 2008
Yigal Chripun wrote:
> Bill Baxter wrote:
>> Jarrett Billingsley wrote:
>>> "janderson" <askme at me.com> wrote in message
>>> news:fnem61$2054$1 at digitalmars.com...
>>>
>>>> Personally I'd make it a class. Yes its going to go on the heap
>>>> however the resizeable array part or whatever the container
>>>> contains, will probably go on the heap anyway.
>>>
>>> Good point. Also keep in mind that even if it's a class, it can be
>>> allocated on the stack in functions if you use 'scope x = new X()',
>>> so there's at least one heap allocation avoided.
>>
>> And if it's a struct it can be allocated on the heap using new if you
>> like.
>>
>> I would be much more inclined to use classes for containers if they
>> either didn't require new, or could be new'ed at point of declaration
>> (like I think they can in Java?).
>>
>> This scattering of information all over the place is one of the things
>> that annoys me most about C++.
>>
>> // Annoying
>> class D {
>> MyContainer c; // must remember to 'new' this later in constructor
>> int[] d; // no worries, it's good.
>> MyStructContainer e; // also no worries
>>
>> ...
>> this() {
>> c = new MyContainer;
>> }
>> }
>>
>> // This would be less annoying
>> class D {
>> MyContainer c = new MyContainer;
>>
>> ...
>> this() {}
>> }
>>
>> // Or this
>> class D {
>> scope MyContainer c;
>>
>> ...
>> this() {}
>> }
>>
>> And the second reason I think containers should be structs is because
>> if you want to "upgrade" some existing code from using a built-in
>> array or AA to using a custom container, it's much less headache if
>> it's a struct-based container. Also if you want to write generic code
>> that can handle built-in and custom containers, then it's going to be
>> easier if your custom containers are structs.
>>
>> I think main important difference is the way copying is handled, but
>> unfortunately "places where a container of type X is copied and
>> subsequently it is assumed that X.member is a distinct pointer" is
>> pretty difficult to grep for.
>>
>> Initialization is also different but you initialize things far less
>> often than you pass them around or assign them to other variables.
>> Initialization patterns are also easier to grep for.
>>
>> That's my 2c.
>>
>> --bb
>
> the way it's done in other oop languages like java, c#, etc:
> there's a hierarchy of interfaces and separate implementations. so as a
> user i use for example :
>
> List<Type> variable = new SomeImplClass();
>
> if i have a function that iterates over a list of stuff i don't need to
> know what implementation was chosen i just rely on the interface. also
> functions should use the most general interface that suits the problem.
> so i can use a
>
> func(container con, other params... )
>
> in order to do similar with structs you need to use template functions
> and you don't have a way to insure that all containers have that same
> base "container" interface (isn't the new c++ standard tries to solve it
> with concepts?). also if i have different container types that creates
> overhead in the executable size (code duplication).
>
> -- Yigal
>
Also, you can design with run-time polymorphism but when necessary go
back to the STL style of compile-time polymorphism.
If you define a final scope class you get (almost) a struct (only
without manual memory management). scope puts your class on the stack,
and final makes its methods non-virtual. so you get almost all the
performance benefits of structs.
You could put that on the class definition itself, but I think that
should be better used at the client side which should know what s/he
prefers.
i.e. an application developer would probably use it as is (like in
Java/C#), and more advanced users of the library could decide for
themselves what kind of overhead tradeoffs are suitable for their code
(stack vs. heap; runtime vs. compile-time polymorphism...).
-- Yigal
More information about the Digitalmars-d
mailing list