POV-Ray : Newsgroups : povray.off-topic : A tale of two cities : Re: A tale of two cities Server Time
29 Jul 2024 06:20:37 EDT (-0400)
  Re: A tale of two cities  
From: Warp
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

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