From: sturlamolden on
On 3 Aug, 02:47, Roy Smith <r...(a)panix.com> wrote:

> This one I don't understand.  Yes, I get RAII, but surely there are
> valid reasons to allocate memory outside of constructors.  Containers
> which resize themselves (such as std::vector) are one obvious example.

That is because an exception might skip an arbitrarily placed delete[]
or std::fclose when it rewinds the stack, so to avoid resource leaks
they must be places inside a destructor of an object on the stack
(which will be called).

This is unsafe, anyone who writes this in C++ should be flogged:

void foobar()
{
std::FILE *fid = fopen("whatever");
// some code here
std::fclose(fid);
}


This idiom is safer :

struct File {
std::FILE *fid;
File(const char *name) {
// acquire resource in constructor
fid = std::fopen(name);
if (!fid) throw some_exception;
}
~File() {
// free resource in destructor
if(fid) std::flose(fid);
}
};

void foobar()
{
File file("whatever");
// some code here
}

It is for the very same reason we should use std::vector instead of
new[] for arrays. It is why new and delete should only be used inside
constructors/destructors. It also why C++ has references in addition
to pointers.

Which means this is bad in C++, as new and delete is arbitrarily
placed:

void foobar()
{
File *myfile = new File("whatever);
// some code here
delete myfile;
}

An object should go on the stack, because if an exception is thrown,
we need the destructor call. Which is why this (as shown above) is
ok:

void foobar()
{
File file("whatever");
// some code here
}

This is the kind of gotchas that allows C++ to shoot your leg off.

In comparison C is much more forgiving, because there is no exceptions
(unless you use setjmp/longjmp). This is ok in C, but not in C++:

void foobar()
{
FILE *fid = fopen("whatever");
// some code here
fclose(fid);
}

For the same reason we can place malloc and free wherever we like in C
code. But in C++ we must restrict std::malloc and std::free (as well
as new and delete) to constructor and destructor pairs.

This kind of design is mandatory to make safe C++ programs. But it is
not enforced by the compiler. And since the majority of C++
programmers don't obey by these rules, Java and C# tends to produce
far less runtime errors and memory/resource leaks. And C++ textbooks
tends to avoid teaching these important details. I'm inclined to
believe it is because the authors don't understand it themselves.

Objects on the stack are also required for operator overloading in C+
+. A common novice mistake is this:

std::vector<double> *myvec = new std::vector<double>(10);
myvec[5] = 10.0; // why does the compiler complain?????

And then the novice will spend hours contemplating why the stupid
compiler claims the type of myvec[5] is std::vector<double>. There was
recently a post to the Cython mailing list claiming there is a bug in
Cython's auto-generated C++ because of this. But this is how it should
be:

std::vector<double> myvec(10);
myvec[5] = 10.0; // ok

And now we see why C++ has references, as that is how we can
efficiently reference and object on the stack without getting the
operator overloading problem above.

C++ is good, but most programmers are better off with C. It has fewer
gotchas. And if we need OOP, we have Python...

Sturla














From: sturlamolden on
On 3 Aug, 04:03, sturlamolden <sturlamol...(a)yahoo.no> wrote:

> struct File {
>     std::FILE *fid;
>     File(const char *name) {
>         // acquire resource in constructor
>         fid = std::fopen(name);
>         if (!fid) throw some_exception;
>     }
>     ~File() {
>         // free resource in destructor
>         if(fid) std::flose(fid);
>     }
>
> };

And since this is comp.lang.python, I'll add in that this sometimes
applies to Python as well. Python, like C++, can have the call stack
rewinded by an exception. If we call some raw OS resource allocation,
e.g. malloc or fopen using ctypes, we have to place a deallocation in
__del__ (and make sure the object is newer put in a reference cycle).
The safer option, however, is to use a C extension object, which is
guaranteed to have the destructor called (that is, __dealloc__ when
using Cython or Pyrex).

If we place raw resource allocation arbitrarily in Python code, it is
just as bad as in C++. But in Python, programmers avoid this trap by
mostly never allocating raw OS resources from within Python code. E.g.
Python's file object is programmed to close itself on garbage
collection, unlike a pointer retured from fopen using ctypes.

Sturla





From: Roy Smith on
In article
<7d95c0d3-718d-4958-9364-263c833f1835(a)i24g2000yqa.googlegroups.com>,
sturlamolden <sturlamolden(a)yahoo.no> wrote:

> On 3 Aug, 02:47, Roy Smith <r...(a)panix.com> wrote:
>
> > This one I don't understand. �Yes, I get RAII, but surely there are
> > valid reasons to allocate memory outside of constructors. �Containers
> > which resize themselves (such as std::vector) are one obvious example.
>
> That is because an exception might skip an arbitrarily placed delete[]
> or std::fclose when it rewinds the stack...

Well, OK, but there's still nothing wrong with allocating memory outside
of constructors, as long as you make sure the destructor cleans it up.
Or you have made some other arrangements to make sure it's cleaned up
(try/catch, auto_pointer, etc).
From: Aahz on
In article <roy-788377.21035502082010(a)news.panix.com>,
Roy Smith <roy(a)panix.com> wrote:
>In article <i37ire$7gd$1(a)panix5.panix.com>, aahz(a)pythoncraft.com (Aahz)
>wrote:
>>
>> http://www.netfunny.com/rhf/jokes/98/May/stroustrup.html
>
>The same story has been floating around for eons, just with the names
>changed. I saw one where Wirth was ostensibly making fun of the people
>who didn't understand that Pascal was all just a joke.
>
>I'm sure if you go back far enough, you can find a McCarthy / Lisp
>version. It probably goes something like, "So, anyway, we tried to
>figure out what was the most absurd way to abuse punctuation we could
>imagine. Somebody suggested that every program would have to end with
>37 close parentheses. When we finally stopped laughing, we started
>sketching out a grammar on the chalkboard that would let us do that".

http://www.netfunny.com/rhf/jokes/90q2/lispcode.html
--
Aahz (aahz(a)pythoncraft.com) <*> http://www.pythoncraft.com/

(You knew I was going to post that, right?)
From: Aahz on
In article <2b473423-0a22-4f4d-943f-31ea2d6020e6(a)z10g2000yqb.googlegroups.com>,
sturlamolden <sturlamolden(a)yahoo.no> wrote:
>
>And since this is comp.lang.python, I'll add in that this sometimes
>applies to Python as well. Python, like C++, can have the call stack
>rewinded by an exception. If we call some raw OS resource allocation,
>e.g. malloc or fopen using ctypes, we have to place a deallocation in
>__del__ (and make sure the object is newer put in a reference cycle).
>The safer option, however, is to use a C extension object, which is
>guaranteed to have the destructor called (that is, __dealloc__ when
>using Cython or Pyrex).

Actually, with Python 2.6 or later, the Pythonic solution is to use
``with``.
--
Aahz (aahz(a)pythoncraft.com) <*> http://www.pythoncraft.com/

"....Normal is what cuts off your sixth finger and your tail..." --Siobhan