POV-Ray : Newsgroups : povray.off-topic : C++: Seriously? : C++: Seriously? Server Time
28 Jul 2024 16:17:52 EDT (-0400)
  C++: Seriously?  
From: Orchid Win7 v1
Date: 21 Nov 2013 14:57:00
Message: <528e658c$1@news.povray.org>
Today, something blew my mind.

I was surfing the net, and I happened to wonder about how best ensure 
stuff gets freed while coding in C++. So I went to Stack Overflow. There 
was an accepted answer about RAII - but right below it, with 5x the 
up-votes, was an answer that basically said

   Everybody says RAII, and that's a good answer. But there's a better 
one: DON'T allocate dynamic memory in the first place! That is, rather 
than writing

   Foo * foo = new Foo();

just write

   Foo foo();

Reflecting on this for a moment, I saw the wisdom of it. If your stuff 
isn't dynamic, you can never ever forget to free it, leave it dangling, 
or have any of the other problems associated with manual memory 
allocation. (About the worst thing you can do is give somebody else a 
pointer to it - don't do that!)

But then I wondered... how can I apply that here?

   char * buffer = new char[1024];
   stream.read(buffer, 1024);
   ...stuff...
   delete[] buffer;

The thing that actually confused me was what the syntax for creating a 
non-dynamic array is - I've never seen anybody do that before. Ever. 
(Not in C or C++, anyway.) It turns out the answer is pretty trivial:

   char buffer[1024];
   stream.read(buffer, 1024);

Now you don't have to *care* that the function might have fifteen return 
statements, or that stuff might throw exceptions... your memory will 
*always* be deallocated when you leave. Because that's how stacks work.

But then somebody else pointed out that this is find for a 1KB buffer, 
but probably a bad idea for a 10MB one. (It also fails if you don't 
statically know how much data you want - which is pretty much the 
*original* reason for inventing dynamic allocation in the first place...)

The suggested solution? "Why don't you just use a std::vector<char>?"

Erm... because std::vector<char> /= char *. One is basically an 
unstructured chunk of arbitrary memory, this other is a complex 
implementation-dependent data structure.

"What's wrong with using vector.front()?"

...

My mind is blown.

OK, so the documentation says that vector.front() gives you a reference 
to the first element of the vector. Nothing surprising there. However, 
if you try to pass that to stream.read()... Woah, that's a whole *bunch* 
of assumptions, right there! o_O

The documentation guarantees that what gets returned is a reference to 
the first element. Firstly, I wasn't actually aware you could even use a 
reference as a pointer; I thought they were separate concepts. But 
secondly, I had assumed that the actual location of vector elements was 
implementation-defined; they might be in a tree, a linked list, a table 
or tables... anything!

But this code... this crazy code seems to be *assuming* that all the 
elements always just happen to be perfectly contiguous in memory.

I'm still trying to figure out whether this audacious assumption about 
the internal behaviour of a library class is more or less evil than just 
trying to do manual memory management correctly...

   Manual memory management? Pretty evil.

   Relying on internal library implementation details? Pretty evil.

Maybe the set of coding evilness is only partially ordered...


Post a reply to this message

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