POV-Ray : Newsgroups : povray.off-topic : A tale of two cities Server Time
1 Nov 2024 05:21:05 EDT (-0400)
  A tale of two cities (Message 1 to 10 of 105)  
Goto Latest 10 Messages Next 10 Messages >>>
From: Invisible
Subject: A tale of two cities
Date: 13 Mar 2012 06:11:41
Message: <4f5f1d5d$1@news.povray.org>
Or rather, a tale of two IDEs for two programming languages.

Yesterday I downloaded and installed Visual C++ 2010 Express. (Can you 
guess which language that's for?) The installation takes /forever/. It's 
one of those programs where you "download the installer" and get a 20KB 
file that just runs the downloader for the /real/ installation program. 
(Why the **** do people do that?!) Still, at least once it's installed, 
it runs fairly fast.

In common with all known IDEs, hitting the "new project" button creates 
a project with /way/ more useless boilerplate code than you will ever 
need. I mean, it creates about half a dozen source files - two separate 
C++ files, three header files, etc. Which is completely overkill just 
for implementing Hello World. (It also sets the tab depth to something 
like 18 spaces or something equally absurd.)

My C++ is very rusty. Hell, I wasn't even that good in the first place! 
But deleting all the unwanted files and starting again from scratch, I 
was able to implement Hello World from memory without needing to look 
anything up. So that's a good start.

Now for my next trick, a Huffman encoder. In most languages it's 
trivially easy to implement, and yet it uses a surprising amount of 
language features. And, uh, yeah... I can't implement this. It's the 
damnedest thing, I swear I already wrote this code once... but I can't 
find it anywhere, so maybe I'm imagining it.

Anyway, C++ employs a manual memory management model. Surprisingly, if 
you can get away with using only STL containers, you don't have to know 
or care that this is the case. All that template magic neatly takes care 
of the problem for you. And that's great.

I made all the usual beginner's stupid mistakes - e.g., passing data 
structures by value, and then wondering why my alterations aren't 
visible from outside the function. (Most OO languages default to passing 
by reference. But then, most OO languages provide automatic memory 
management too...)

The real sticking point was when I started trying to use abstract 
classes. It seems that you cannot have a variable of an abstract class. 
(Because creating that variable would require creating an instance of an 
abstract class, which is illegal.) You can only have a variable that 
/points to/ such a value. (Because then what it points to can actually 
be some concrete subclass.)

That's all fine and logical and everything, but there's a nasty snag: 
Now you have to care about memory management. And there's no way around it.

I was eventually able to get the program to produce the correct output. 
However, it uses the dreaded "new" operator. In particular, it does 
/not/ use the "delete" operator anywhere. In other words, it leaks. I 
have literally no idea how to fix this. I can't think of any way of 
doing it that won't result in double-freeing objects. That's mainly 
because I can't put responsibility for object creation (and hence object 
destruction) in the logical place. And /that/ is because I don't have 
some of the necessary technical understanding.

I found a reasonable C++ introduction at cplusplus.com, but it doesn't 
explain several technical points which I'm unclear on. Does anybody know 
of a better resource? (Obviously, a Google search will turn up millions 
of results. It's hard to know which ones are /good/ resources, however.)



Having spent a few hours on that, I decided to turn my attention to 
Java. Now I've coded fairly extensively in Java in the past, but that 
was about 10 years ago. (Jesus Christ I'm old now! >_< ) I still 
remember most of the syntax, but I haven't actually tried to /compile/ 
any code for a very long time. I'm not sure if I'll remember how...

So I downloaded the NetBeans IDE for Java SE. Which immediately told me 
that I have to install the Java SE JDK before running the installer. 
Gee, thanks for that. :-P You couldn't have made that clearer from the 
download page, no?

So, 80MB for NetBeans, another 80MB for the JDK itself, and finally I'm 
in business. Now, I'm not saying NetBeans is /inefficient/, but 
swallowing 200MB of RAM just because I double-clicked the icon to open 
the IDE does seem /just a tad excessive/ to me. Initially I was just 
trying to figure out how to work the thing, but as I started to learn my 
way around and started trying to actually /do/ stuff, the IDE seemed 
unacceptably unresponsive. (Quite apart from visually /looking/ like 
something baked by an open source committee rather than being a polished 
commercial product.)

Like VS, asking NetBeans for a basic project generates a plateful of 
useless code that you then have to waste time deleting. (Apparently 
there's an Ant script somewhere too... whatever the hell that is.) It 
also sets the tab depth far, far too deep. But unlike VS, it also seems 
to /insist/ on incorrectly putting the open bracket on the same line as 
the declaration it begins. (This incorrect practise is also common in 
C++, and yet I didn't seem to have this problem with VS.) It's easy 
enough to manually fix, I suppose.

While VS does syntax highlighting and occasionally pops up a list of 
method names or something (usually a few seconds too late to be useful, 
or using out of date type information), NetBeans seems a little more 
impressive. Oh, it still does syntax highlighting. (With some rather 
unhelpful colour choices.) And it still pops up out-of-date method lists 
that actually get in the way far more than they help. But it goes a few 
steps further.

For example, Java is such a retarded language that the only way to copy 
some stuff from one array to another is to manually write a loop. So I 
wrote a loop. And a little box popped up saying "manual array copy 
detected - replace with System.arraycopy()?" I clicked the button. All 
the temporary variables vanished, and were replaced with the above 
method call, with the correct source and destination, and even the 
correct array indices. I'm impressed.

Or rather, I'm impressed at the IDE. Implementing array copying as a 
static method on a general utility class? Yeah, /that/ sounds like 
fantastic OO library design! :-P Really, Java? I mean, really? Still, at 
least you don't need to use an abstract factory factory to use it. The 
syntax is quite straight forward.

Also interesting is that when you call a method, it seems to take a 
guess at what variables currently in scope are of the correct type, and 
fills that in for you automatically. Handy when it works, mildly 
irritating when it doesn't.

Needless to say, Hello World was no challenge at all. Implementing my 
Huffman encoder was a little more tricky. When I ran it, I got a null 
pointer exception. Amusingly [or not], it is apparently impossible to 
make the IDE halt the program at the location where the exception is 
thrown. Even in debug mode, it just runs the program, prints out the 
exception, and then quits. No way of, you know, inspecting the program 
state at the moment of the exception to actually see what the problem 
is, or anything like that. In fact, come to mention it, I can't find any 
way at all to single-step through the program. VS did all of this and 
more. :-P

As always with these types of problems, I eventually discovered that I'd 
forgotten to initialise something in the code. (An empty array is of 
course /not/ the same thing as a null pointer...) Once I fixed that, it 
all worked just fine. If I had had access to a debugger that would 
actually tell me which field it was that was uninitialised, it would 
have taken seconds to figure out the problem and fix it. It only took 
half an hour because I had to sprinkle print() all over the place until 
the problem became apparent.

So there we are. I doubt I'd remember much about the AWT (although, 
didn't they deprecate that in favour of Swing?), but I can certainly 
still write algorithmic code in Java without much ado. Maybe today I'll 
try something more ambitious with it. If I can avoid throwing the IDE 
out of a window.

(Is it just me? "Net Beans"? It's an IDE. What the /hell/ does that have 
to do with networking? The "beans" part I kinda get; everything 
Java-related has to be themed on coffee or coffee beans. But why "net"?)


Post a reply to this message

From: John VanSickle
Subject: Re: A tale of two cities
Date: 13 Mar 2012 07:33:47
Message: <4f5f309b$1@news.povray.org>
On 3/13/2012 6:11 AM, Invisible wrote:

> I was eventually able to get the program to produce the correct output.
> However, it uses the dreaded "new" operator. In particular, it does
> /not/ use the "delete" operator anywhere. In other words, it leaks. I
> have literally no idea how to fix this. I can't think of any way of
> doing it that won't result in double-freeing objects. That's mainly
> because I can't put responsibility for object creation (and hence object
> destruction) in the logical place. And /that/ is because I don't have
> some of the necessary technical understanding.
>
> I found a reasonable C++ introduction at cplusplus.com, but it doesn't
> explain several technical points which I'm unclear on. Does anybody know
> of a better resource? (Obviously, a Google search will turn up millions
> of results. It's hard to know which ones are /good/ resources, however.)

Good memory management in C and C++ are things you really have to learn 
as you go along.  You can probably encapsulate your heap object pointers 
into a handler class, but you probably have some learning to go before 
you're ready to implement that.

I think the best way to go is to decide whether a given pointer 
represents an object that is created on the heap and is owned by the 
pointer's container, or if it just refers to an object that is owned by 
some other container.  The owner takes care of deleting its objects 
created on the heap, but otherwise objects get left alone.

> (Is it just me? "Net Beans"? It's an IDE. What the /hell/ does that have
> to do with networking? The "beans" part I kinda get; everything
> Java-related has to be themed on coffee or coffee beans. But why "net"?)

Apparently Java's developers are focused on its Web capabilities, and 
are trying to emphasize that.

Regards,
John


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 13 Mar 2012 11:03:31
Message: <4f5f61c3$1@news.povray.org>
On 13/03/2012 11:33 AM, John VanSickle wrote:
> On 3/13/2012 6:11 AM, Invisible wrote:
>
>> I was eventually able to get the program to produce the correct output.
>> However, it uses the dreaded "new" operator. In particular, it does
>> /not/ use the "delete" operator anywhere. In other words, it leaks.
>
> Good memory management in C and C++ are things you really have to learn
> as you go along. You can probably encapsulate your heap object pointers
> into a handler class, but you probably have some learning to go before
> you're ready to implement that.
>
> I think the best way to go is to decide whether a given pointer
> represents an object that is created on the heap and is owned by the
> pointer's container, or if it just refers to an object that is owned by
> some other container. The owner takes care of deleting its objects
> created on the heap, but otherwise objects get left alone.

Sure. I get all that. The problems I'm facing are technical, not 
theoretical. I know what code I want to write, but I don't know how to 
use the language features to write that code.

>> (Is it just me? "Net Beans"? It's an IDE. What the /hell/ does that have
>> to do with networking? The "beans" part I kinda get; everything
>> Java-related has to be themed on coffee or coffee beans. But why "net"?)
>
> Apparently Java's developers are focused on its Web capabilities, and
> are trying to emphasize that.

By sticking "net" in the name? Heh, that's like inventing a scripting 
language and naming it after Java to try and latch onto its 
popularity... Oh, wait. Somebody did that. :-P


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 13 Mar 2012 11:15:57
Message: <4f5f64ad$1@news.povray.org>
On 13/03/2012 10:11 AM, Invisible wrote:
> So, 80MB for NetBeans, another 80MB for the JDK itself, and finally I'm
> in business. Now, I'm not saying NetBeans is /inefficient/, but
> swallowing 200MB of RAM just because I double-clicked the icon to open
> the IDE does seem /just a tad excessive/ to me. Initially I was just
> trying to figure out how to work the thing, but as I started to learn my
> way around and started trying to actually /do/ stuff, the IDE seemed
> unacceptably unresponsive. (Quite apart from visually /looking/ like
> something baked by an open source committee rather than being a polished
> commercial product.)

I eventually gave up with NetBeans. It's just too cripplingly slow. (I 
did not have this problem with VS.) If I type something and have to wait 
/4 seconds/ for anything to appear on the screen, that's too slow, IMHO.

Seriously. Once I got to a handful of files, amounting to a grand total 
of 6KB of Java source, performance became unacceptably poor. I also love 
the way that running the program randomly fails from time to time. You 
click "run", and it says "build successful", followed by "cannot find 
compiled code". But if you click the button enough times, eventually it 
runs perfectly. So... WTF is wrong with it?!

In all, I was spending /far/ too much time fighting the IDE and not 
enough time actually coding stuff. So I switched back to a text editor 
and a command prompt. (Amusing how installing the JDK doesn't add any of 
the Java binaries to the search path. If by "amusing" you mean "tedious 
and annoying"...)

Some of you may remember that logic simulator I built in Haskell a while 
back. If I recall, I challenged Warp to implement it in C++, and he 
couldn't even figure out how the heck it works. (I must admit, it's a 
loopy piece of coding.) Perhaps a Java implementation will be less 
mind-bending for any curious souls - or perhaps not, IDK. Either way, 
it'll be a while before *I* can implement it in C++. (!)

Also, I think I might have to build a parser for Java. Because, damnit, 
writing stuff like

   new Or(new And(new Equals(new NameVar("x"), new IntegerConst(1)), new 
Equals(new NameVar("y"), new IntegerConst(2))), ...

becomes tedious /rapidly/!

I keep hearing that Java has added generics since I last worked with it. 
I find it amusing that we can now write HashMap<Foo, Bar>, and yet we 
have type signatures like

   public Object get(Object key);

Really? I mean, really? Should that not be

   public V get(K key);

or similar? Is that not the entire /point/ of generics?

Then we have fun such as Object.clone(), which is [still] defined to 
return Object. So you get to write stuff like

   java.util.HashMap<Variable, Expression> copy = 
(java.util.MashMap<Variable, Expression>) old.clone();

And of course, no way to define type aliases (and no automatic type 
inference either), so if I decide to change the HashMap for, I don't 
know, a TreeMap perhaps, I'm going to have to change type signatures in 
a dozen places. Gee, thanks for that. :-P

Even more fun, apparently writing the above code is an "unsafe, 
unchecked construct" - or so the compiler warns me with /every single 
damned compile/. Despite the fact that the above is statically 
guaranteed to always work. *sigh*

Yes, Java /still/ sucks. :-P


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 13 Mar 2012 11:46:11
Message: <4f5f6bc3$1@news.povray.org>
On 13/03/2012 03:15 PM, Invisible wrote:
> I keep hearing that Java has added generics since I last worked with it.
> I find it amusing that we can now write HashMap<Foo, Bar>, and yet we
> have type signatures like
>
> public Object get(Object key);
>
> Really? I mean, really? Should that not be
>
> public V get(K key);
>
> or similar? Is that not the entire /point/ of generics?

Interesting fact: It seems the latest JDK implements /two/ versions of 
the same interface.

public interface Iterator
{
   public boolean hasNext();
   public Object next();
   public void remove();
}

public interface Iterator<E>
{
   public boolean hasNext();
   public E next();
   public void remove();
}

If you accidentally forget to mention the element type, you get the old 
version of the interface, with all its type unsafety. Isn't that great? 
*sigh*


Post a reply to this message

From: Warp
Subject: Re: A tale of two cities
Date: 13 Mar 2012 11:56:43
Message: <4f5f6e3a@news.povray.org>
Invisible <voi### [at] devnull> wrote:
> In common with all known IDEs, hitting the "new project" button creates 
> a project with /way/ more useless boilerplate code than you will ever 
> need.

  Probably because you created a new *Windows* project, rather than a
portabla command-line one.

> The real sticking point was when I started trying to use abstract 
> classes. It seems that you cannot have a variable of an abstract class. 
> (Because creating that variable would require creating an instance of an 
> abstract class, which is illegal.) You can only have a variable that 
> /points to/ such a value. (Because then what it points to can actually 
> be some concrete subclass.)

  Dynamic binding, abstract classes, and even inheritance, are needed
in practice significantly less often than one might think (especially
if one comes from a background where that's basically the only way of
doing anything).

  In quite many cases it's enough to have classes with no dynamic binding
nor inheritance, and which are handled by value (at least if they contain
only moderate amount of data). In the case of a huffman coder, I really
don't understand what do you need abstract classes for. (There *is* such
a thing as over-designing, when talking about OOP.)

  In many cases if you design your program such that you don't need
dynamic binding, your program will often become more efficient in terms
of both speed and memory usage. (Not because dynamic binding would be
inefficient, as it isn't, but because dynamic memory allocation is, and
if we are talking about abstract classes, then dynamic memory allocation
usually goes hand in hand with it.)

  (Inheritance in itsef is not bad in this sense, because C++ does not
force dynamic binding. Base classes can sometimes be used to group common
implementations into a single module, to avoid code repetition. Using an
inherited class is in no way less efficient than one that has no parent
class at all. However, as said, even inheritance is less often necessary
in practice than one might think.)

> I was eventually able to get the program to produce the correct output. 
> However, it uses the dreaded "new" operator. In particular, it does 
> /not/ use the "delete" operator anywhere. In other words, it leaks. I 
> have literally no idea how to fix this. I can't think of any way of 
> doing it that won't result in double-freeing objects. That's mainly 
> because I can't put responsibility for object creation (and hence object 
> destruction) in the logical place. And /that/ is because I don't have 
> some of the necessary technical understanding.

  If you are an experienced, competent c++ programmer, each time you have
to write the dreaded keyword 'new', it should give you a feeling of unease,
and the instinctive desire to think of better alternatives. This even if
you have no problems whatsoever with memory management in this situation
(eg. because you are using a smart pointer). That's because 'new' is not
only a source of leaks, but also it's inefficient.

  There are, of course, situations where 'new' is the only and best
solution. For example, if you are implementing your own dynamic array
(which has something that std::vector does not provide), then there's
no problem. However, the usage of 'new' should in this case be tightly
restricted to happen inside this dynamic array class, strictly controlled
by it. Maximum encapsulation of the memory management is the key.

  If, for some strange reason, you need to allocate individual objects
dynamically with 'new', then you should either use a smart pointer to
handle it (C++11 provides std::unique_ptr and std::shared_ptr for this
purpose), or you should write a class that acts as such (in other words,
which acts kind of like a data container containing one element: The
allocated object.)

  Writing 'new' outside of a class member function (of a class that handles
that allocated memory, of course) is always a risk. Even if you make sure
there's a corresponding 'delete' at the end of the function, your code
will not be exception-safe (because if an exception happens before that
'delete', the allocated object will be leaked; the exception is if you
use a smart pointer such as std::unique_ptr to handle it).

  In practice I don't remember having to write 'new' even once outside
of a class that handles the allocated memory. Smart pointers are fine
and all, but they are seldom needed in practice.

  Now, writing a class that properly manages its dynamically allocated
memory is a non-trivial task of its own.

-- 
                                                          - Warp


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 13 Mar 2012 12:32:04
Message: <4f5f7684$1@news.povray.org>
On 13/03/2012 03:56 PM, Warp wrote:
> Invisible<voi### [at] devnull>  wrote:
>> In common with all known IDEs, hitting the "new project" button creates
>> a project with /way/ more useless boilerplate code than you will ever
>> need.
>
>    Probably because you created a new *Windows* project, rather than a
> portabla command-line one.

Nope. I specifically requested "console application".

>    Dynamic binding, abstract classes, and even inheritance, are needed
> in practice significantly less often than one might think (especially
> if one comes from a background where that's basically the only way of
> doing anything).

Perhaps. Although in a sense, I'm not actually "interested" in building 
a specific application here, I'm interested in figuring out how 
inheritance and so forth actually works in C++.

> In the case of a huffman coder, I really
> don't understand what do you need abstract classes for. (There *is* such
> a thing as over-designing, when talking about OOP.)

The most obvious way to implement this is to physically build a binary 
tree. That requires either inheritance, or else doing something sly with 
unions. (Or even being /really/ dirty and just having one node type, and 
ignoring the unused fields.)

Now for the /encoding/ part itself, I don't actually need a physical 
tree. I have a vague recollection that last time I did this, I ended up 
cheating and just storing a vector of codewords, and manually munging 
that. It's a lot less elegant, but avoids dynamic allocation. (Or 
rather, no it doesn't, but it hides it in STL containers, so you don't 
have to do it manually.)

This application is just supposed to be the "warm up" for my next 
project, which will involve building complex expression trees. I really 
don't see how you can get away with no dynamic binding when each node 
type needs to be processed differently. Unless you go all non-OO and try 
to implement node type dispatch manually...

>    In many cases if you design your program such that you don't need
> dynamic binding, your program will often become more efficient in terms
> of both speed and memory usage.

I guess to some extent it depends on whether your goals are efficiency 
or maintainability. Certainly the code I'm trying to write will probably 
take milliseconds to execute, whichever way I implement it. If I was 
writing something high-performance, I might care about such things.

>    If you are an experienced, competent c++ programmer, each time you have
> to write the dreaded keyword 'new', it should give you a feeling of unease,
> and the instinctive desire to think of better alternatives.

Well, I did try to think of a way around it. But I failed to come up 
with a solution.

>    There are, of course, situations where 'new' is the only and best
> solution. For example, if you are implementing your own dynamic array
> (which has something that std::vector does not provide), then there's
> no problem. However, the usage of 'new' should in this case be tightly
> restricted to happen inside this dynamic array class, strictly controlled
> by it. Maximum encapsulation of the memory management is the key.

The problem is, I want to copy some data, but since I don't know what 
class it belongs to, I have no idea how big it will be. Presumably 
there's some way around that, but damned if I know what it is... Like I 
say, I need to find a more thorough reading resource that explains this 
stuff properly.

>    Now, writing a class that properly manages its dynamically allocated
> memory is a non-trivial task of its own.

Is that not just a case of allocating the memory correctly in the 
constructor, and freeing it properly in the destructor? (I mean, 
assuming nobody tries to copy the object or free its dynamic memory or 
anything like that...)


Post a reply to this message

From: Warp
Subject: Re: A tale of two cities
Date: 13 Mar 2012 13:20:55
Message: <4f5f81f5@news.povray.org>
Invisible <voi### [at] devnull> wrote:
> > In the case of a huffman coder, I really
> > don't understand what do you need abstract classes for. (There *is* such
> > a thing as over-designing, when talking about OOP.)

> The most obvious way to implement this is to physically build a binary 
> tree. That requires either inheritance, or else doing something sly with 
> unions. (Or even being /really/ dirty and just having one node type, and 
> ignoring the unused fields.)

  I don't see why you need different types of objects for such a binary
tree. Each object can be identical to each other in structure. (If in
some nodes some of the fields are unused, so what? It will still be
significantly more efficient than dynamic binding.)

  You don't need to mess with unions unless you really, really need to
make the objects as small as physically possible. However, making them
that small is completely moot if you are going to allocate them
individually anyways (the allocation bookkeeping overhead will nullify
any space saving you could get from shaving off a few bytes using unions.)
It would only make a significant difference if you used arrays of
objects as your tree data structure, rather than allocating objects
individually, and there were tons and tons of elements.

> Now for the /encoding/ part itself, I don't actually need a physical 
> tree. I have a vague recollection that last time I did this, I ended up 
> cheating and just storing a vector of codewords, and manually munging 
> that. It's a lot less elegant, but avoids dynamic allocation. (Or 
> rather, no it doesn't, but it hides it in STL containers, so you don't 
> have to do it manually.)

  Using an array of objects (rather than individually allocated objects)
doesn't completely avoid memory allocation, but it minimizes their amount,
which is often very significant. (In other words, if your program makes
20 allocations instead of a million, it will have a significant impact
on the speed of the program.)

> This application is just supposed to be the "warm up" for my next 
> project, which will involve building complex expression trees. I really 
> don't see how you can get away with no dynamic binding when each node 
> type needs to be processed differently. Unless you go all non-OO and try 
> to implement node type dispatch manually...

  If you really must have nodes of differing types, then it will become
complicated from the point of view of memory management. Lack of garbage
collection can be a b**** sometimes. (Not that it's impossible; it just
requires a lot of care and strict coding practices to get it right. This
is something you usually want to avoid altogether, if possible.)

  Of course your nodes could simply be (smart) pointers of a base class
type, but then you will be making twice as many allocations (because for
each node you will be allocating the node itself, which is a smart pointer,
*and* the object that the node is pointing to), which is even worse from
an efficiency point of view. It becomes simpler like this, but don't expect
extreme speed. (Haskell probably would beat C++ in this situation.)

  It's sometimes quite a bummer, but when writing efficient C++ you have
to always think "how many memory allocations will this perform?" (even,
and especially, when using STL data containers). The less individual
memory allocations are done, the better. (But of course that's not the
only thing that affects speed, but it's the one major thing not related
to the algorithm itself that does.)

  I have to grant that languages like Java are better at this because
there you don't have to worry about how many allocations are performed
(as JVM's have a significantly faster memory allocation than the C/C++
runtime.)

> >    In many cases if you design your program such that you don't need
> > dynamic binding, your program will often become more efficient in terms
> > of both speed and memory usage.

> I guess to some extent it depends on whether your goals are efficiency 
> or maintainability.

  Avoiding dynamic binding does not automatically mean that your program
becomes more complicated and harder to maintain. In fact, it can sometimes
mean the opposite. Sometimes your programs actually become *simpler* and
much easier to understand. Full OOP (beyond simple encapsulation using
classes) is not always the universal panacea for clarity and maintainability.
(Of course this depends on each individual case.)

> Certainly the code I'm trying to write will probably 
> take milliseconds to execute, whichever way I implement it. If I was 
> writing something high-performance, I might care about such things.

  But even then you have to think which design is easiest in terms of
memory management. The less you have to manage memory manually, the
better. Your program becomes safer and simpler.

> The problem is, I want to copy some data, but since I don't know what 
> class it belongs to, I have no idea how big it will be.

  I didn't understand your problem from that description alone.

> >    Now, writing a class that properly manages its dynamically allocated
> > memory is a non-trivial task of its own.

> Is that not just a case of allocating the memory correctly in the 
> constructor, and freeing it properly in the destructor? (I mean, 
> assuming nobody tries to copy the object or free its dynamic memory or 
> anything like that...)

  The simplest design is to delete the allocated memory in the destructor
(it doesn't really matter where inside the class the memory is allocated
as long as the pointer is kept as 0 when there's nothing allocated) and
then disabling the copy constructor and assignment operators. (In C++98
this is done by declaring them private and not implementing them. In C++11
you can explicitly express this with a keyword.)

  Often this is enough. However, sometimes you would want to be able
to copy and assign objects of that class type around. That's where the
non-triviality kicks in.

  The first problem is: How should the object be copied? There are many
possibilities:

- Perform a deep copy. Every time the object is copied or assigned, all
of the data it's managing is copied. This is the easiest way of managing
copying, but it can be pretty inefficient with large amounts of data (and
because each time you make a copy you need an additional 'new').

- Make the class act as a reference to the managed data, in which case each
copy *shares* the managed data. In this case you need to use reference
counting to know when to delete the data. You also have to design your
program taking into account that the object is acting as a reference to
the data, not as the data itself. (This can work pretty well if your
data object is considered immutable.)

- Perform lazy copying. In other words, copying/assigning the object does
not yet deep-copy the data. Only when the data is modified it will be
copied if it was being shared between more than one object. This makes
copying and assigning more efficient, but accessors less.

- The data is *moved* from the original to the copy. This is very efficient
(because you don't need reference counting or anything else) but can be
quite limiting (because you are not actually copying anything, just moving
the data from one object to another).

  The second problem is that implementing these is not completely trivial
and requires attention to detail and knowing the traps.

-- 
                                                          - Warp


Post a reply to this message

From: Warp
Subject: Re: A tale of two cities
Date: 13 Mar 2012 13:31:25
Message: <4f5f846c@news.povray.org>
Warp <war### [at] tagpovrayorg> wrote:
>   The first problem is: How should the object be copied? There are many
> possibilities:

  If you are wondering which solution the STL data containers use,
it's usually just a simple deep-copy whenever the container is copied
or assigned. (While this is implementation-defined, you can assume that
the vast majority, if not all, of the STL implementations out there use
deep copying.) You should take this into account when using the STL.
(In other words, never needlessly copy/assign a large data container.)

  As said, deep-copying is the easiest/simplest solution in terms of
memory management, but you have to be careful to not be copying them
around without a good reason.

-- 
                                                          - Warp


Post a reply to this message

From: nemesis
Subject: Re: A tale of two cities
Date: 13 Mar 2012 15:27:43
Message: <4f5f9faf$1@news.povray.org>
Invisible escreveu:
> On 13/03/2012 10:11 AM, Invisible wrote:
> I eventually gave up with NetBeans. It's just too cripplingly slow. (I 
> did not have this problem with VS.) If I type something and have to wait 
> /4 seconds/ for anything to appear on the screen, that's too slow, IMHO.

ah, children from the 90's...

> Seriously. Once I got to a handful of files, amounting to a grand total 
> of 6KB of Java source, performance became unacceptably poor.

That's not my (ackowledged little) experience.  And surely not of most 
people working on some hairy shared projects.

> In all, I was spending /far/ too much time fighting the IDE and not 
> enough time actually coding stuff.

cool, now you'll be just fighting a wholesomely stupid language.

*oh, I felt so Darrenish now*

> Some of you may remember that logic simulator I built in Haskell a while 
> back. If I recall, I challenged Warp to implement it in C++, and he 
> couldn't even figure out how the heck it works.

Perhaps you should have told him what the code is supposed to do rather 
than expect someone to figure out what some haskell code is doing.

Here's a challenge for you.  What do these haskell snippets are supposed 
to do?

snippet 1:

((.)$(.))

snippet 2:

f >>= a . b . c =<< g


and for a bonus, guess what this one does:

import System.Environment

foo n = 0 % (0 # (1,0,1)) where
  i%ds
   | i >= n = []
   | True = (concat h ++ "\t:" ++ show j ++ "\n") ++ j%t
   where k = i+10; j = min n k
         (h,t) | k > n = (take (n`mod`10) ds ++ replicate (k-n) " ",[])
               | True = splitAt 10 ds
  j # s | n>a || r+n>=d = k # t
      | True = show q : k # (n*10,(a-(q*d))*10,d)
   where k = j+1; t@(n,a,d)=k&s; (q,r)=(n*3+a)`divMod`d
  j&(n,a,d) = (n*j,(a+n*2)*y,d*y) where y=(j*2+1)

main = putStr.foo.read.head =<< getArgs


no googling, huh? ;)


> Yes, Java /still/ sucks. :-P

Yes and that is a feature by design.

What doesn't suck is the JVM and the tens of thousands of useful libs 
that run atop it.  It's the only truly cross-platform performant VM out 
there.  Think about it, libs you don't actually need to recompile on 
your machine.

And if you don't like java, you can just choose from many languages 
running atop it and leveraging from said libs:  Scala, Jython, JRuby, 
even quite a few Scheme implementations... any haskell work on this front?

BTW, Ant is yet another example of XML-madness:  it's basically a 
verbose XML makefile for java.

-- 
a game sig: http://tinyurl.com/d3rxz9


Post a reply to this message

Goto Latest 10 Messages Next 10 Messages >>>

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.