 |
 |
|
 |
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
(You knew there were going to be a few at some point...)
I just want to make sure I've got this absolutely straight in my head.
So... a reference is the same as a pointer, except that it has nicer
syntax, and you cannot change where it points to?
If I'm understanding this correctly, a "union" is like several structs
with the same base address, and you can treat it was one struct or the
other struct, and it's up to you to remember which which struct you're
currently using it is. (I.e., the language itself provides no way to
distinguish.)
Here's a perverse question: can a union have member functions?
My understanding is that when you create variables, they start off
containing junk unless you initialise them (or their types have
constructors which initialise them to something specific). Is that correct?
Does C++ have a concept of a "null pointer" - i.e., a pointer that
doesn't point to anything valid, and can be detected as such?
How does memory allocation work in C++? If a program fills the heap, do
you have to explicitly *do* something to enlarge the heap, or does it
grow automatically? Does it shrink back again after you release things,
or do you have to request that manually?
There will probably be more questions as I read further. Currently I'm
still attempting to comprehend the concept of a "const volatile variable"...
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible <voi### [at] dev null> wrote:
> I just want to make sure I've got this absolutely straight in my head.
> So... a reference is the same as a pointer, except that it has nicer
> syntax, and you cannot change where it points to?
And there's no null reference. A reference must always be given a
valid object. (Of course it can be given an invalid one by abusing
ugly casting, but then your program will crash or behave erratically.)
> If I'm understanding this correctly, a "union" is like several structs
> with the same base address, and you can treat it was one struct or the
> other struct, and it's up to you to remember which which struct you're
> currently using it is. (I.e., the language itself provides no way to
> distinguish.)
A union is a space-saving trick from C. Suppose you have an array of
elements, and each element can be either an int or a double. You could
do that by making the element a struct with an int and a double:
struct Element
{
int i;
double d;
};
sizeof(Element) == sizeof(int) + sizeof(double)
But since the element is always either an int or a double, never both
at the same time, that feels like a waste of space: You are needlessly
allocating space for both things, even though always one of the things
is always unused.
A union is a way to put both elements at the same location:
union Element
{
int i;
double d;
};
Now sizeof(Element) == sizeof(double)
The element is interpreted as an int if you access 'i' and as a double
if you access 'd'. Of course there's absolutely no type safety here.
If it was initialized as a double and you access it as an integer, you'll
get garbage (whatever the first bytes of the double look like when seen
as an integer).
Since there's no way of distinguishing which type of element it is,
unions are often used like this:
struct Element
{
enum Type { Int, Double };
Type type;
union
{
int i;
double d;
};
};
(Of course in this particular case there's no space saving, but you
get the idea.)
Some people use unions for fancier tricks, such as:
struct Matrix
{
union
{
double v[3][3];
struct
{
double v00, v01, v02, v10, v11, v12, v20, v21, v22;
};
};
};
Now if you have some "Matrix m;", m.v[0][1] and m.v01 are the same thing.
Unions are not very compatible with C++ classes. If you had this:
union Element
{
int i;
std::string s;
};
and then you instantiate it like "Element e;", then what should the
compiler do about the string? Should it call its constructor or not?
It would be useless (and wrong) to construct it if what you want to do
is to use the int. It would be would be wrong to not to construct it
if you want to use the string.
(Constructing it would be wrong because if you then modify the int,
you will be corrupting the string object, and undefined behavior will
follow.)
Likewise: What happens when 'e' is destroyed? Should the destructor
of the string be called or not?
Thus the current standard just says that you can't use class instances
as members of a union, period.
The next C++ standard will relax this limitation a bit in certain cases,
but overall C++ has inherited unions from C and they are not very C++'ish
constructs.
> Here's a perverse question: can a union have member functions?
Yes, but they cannot be virtual.
> My understanding is that when you create variables, they start off
> containing junk unless you initialise them (or their types have
> constructors which initialise them to something specific). Is that correct?
Right (although in some situations it might not be immediately clear
whether the variable is actually being initialized or not).
> Does C++ have a concept of a "null pointer" - i.e., a pointer that
> doesn't point to anything valid, and can be detected as such?
Yes: 0.
> How does memory allocation work in C++? If a program fills the heap, do
> you have to explicitly *do* something to enlarge the heap, or does it
> grow automatically? Does it shrink back again after you release things,
> or do you have to request that manually?
That's something the compiler and the OS take care of. You usually don't
have to worry about it.
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> Invisible <voi### [at] dev null> wrote:
>> I just want to make sure I've got this absolutely straight in my head.
>> So... a reference is the same as a pointer, except that it has nicer
>> syntax, and you cannot change where it points to?
>
> And there's no null reference. A reference must always be given a
> valid object.
Ah yes - because you can't change it later, it must always be pointed at
something when you first create it.
> (Of course it can be given an invalid one by abusing
> ugly casting, but then your program will crash or behave erratically.)
Yeah. Don't do that! ;-)
> A union is a space-saving trick from C.
> A union is a way to put both elements at the same location:
>
> union Element
> {
> int i;
> double d;
> };
>
> Now sizeof(Element) == sizeof(double)
>
> The element is interpreted as an int if you access 'i' and as a double
> if you access 'd'. Of course there's absolutely no type safety here.
> If it was initialized as a double and you access it as an integer, you'll
> get garbage (whatever the first bytes of the double look like when seen
> as an integer).
Right. That's what I figured.
> Since there's no way of distinguishing which type of element it is,
> unions are often used like this:
>
> struct Element
> {
> enum Type { Int, Double };
>
> Type type;
> union
> {
> int i;
> double d;
> };
> };
Right. So you add a tag to tell you what kind of thing it is.
(Incidentally, this is basically what Haskell's "algebraic datatypes"
are. You can write something like "data Number = IntNumber Int |
DoubleNumber Double", and now any function that accepts a "Number" will
accept either an Int or a Double. And it's type-safe because the value
is tagged with a name such as "IntNumber".)
> Some people use unions for fancier tricks, such as:
>
> struct Matrix
> {
> union
> {
> double v[3][3];
> struct
> {
> double v00, v01, v02, v10, v11, v12, v20, v21, v22;
> };
> };
> };
>
> Now if you have some "Matrix m;", m.v[0][1] and m.v01 are the same thing.
That's just devious! :-O
> Unions are not very compatible with C++ classes. If you had this:
>
> union Element
> {
> int i;
> std::string s;
> };
>
> and then you instantiate it like "Element e;", then what should the
> compiler do about the string? Should it call its constructor or not?
> Likewise: What happens when 'e' is destroyed? Should the destructor
> of the string be called or not?
Ooo, ouch!
> Thus the current standard just says that you can't use class instances
> as members of a union, period.
Fair enough.
Actually, it just occurred to me: what would happen if you had a union
of two classes that are both related? When you do foo.bar(), how would
it know which bar() you meant? No wonder they don't allow this stuff...
>> Here's a perverse question: can a union have member functions?
>
> Yes, but they cannot be virtual.
OK. Well I doubt I'll be using unions much anyway, but hey. ;-)
>> My understanding is that when you create variables, they start off
>> containing junk unless you initialise them (or their types have
>> constructors which initialise them to something specific). Is that correct?
>
> Right (although in some situations it might not be immediately clear
> whether the variable is actually being initialized or not).
Yeah, "int x;" and "string x" both look pretty similar, but if I
understand this right, the latter gets initialised (to an empty string?)
>> Does C++ have a concept of a "null pointer" - i.e., a pointer that
>> doesn't point to anything valid, and can be detected as such?
>
> Yes: 0.
So I say "int *x = 0;" and then later I can check that "if (x == 0) ..."?
Does C++ check whether a pointer you're deferencing is zero? Or will it
just segfault?
>> How does memory allocation work in C++? If a program fills the heap, do
>> you have to explicitly *do* something to enlarge the heap, or does it
>> grow automatically? Does it shrink back again after you release things,
>> or do you have to request that manually?
>
> That's something the compiler and the OS take care of. You usually don't
> have to worry about it.
OK.
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible wrote:
> Right. That's what I figured.
And the first thing listed in the union is what gets initialized to the
appropriate type of zero if it's static. So if you have
static union {
double * dp;
long l;
} X;
static union {
long l;
double * dp;
} Y;
then X and Y might start out with different bit patterns if the "null"
pointer on that platform isn't all zero bits.
>>> Does C++ have a concept of a "null pointer" - i.e., a pointer that
>>> doesn't point to anything valid, and can be detected as such?
>>
>> Yes: 0.
>
> So I say "int *x = 0;" and then later I can check that "if (x == 0) ..."?
Yes. Note that in each case, that's technically a cast. The bit pattern
of the pointer doesn't have to be zeros. If it's a null pointer, casting
it to an integer gives you zero, and casting the integer 0 to a pointer
gives you null.
At least in C, the "NULL" macro is more commonly used to me "a pointer
that when cast to an integer yields zero." I think C++ changed this
when it improved the type system.
> Does C++ check whether a pointer you're deferencing is zero? Or will it
> just segfault?
It segfaults, if you're on a machine that can do that. :-)
--
Darren New / San Diego, CA, USA (PST)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible <voi### [at] dev null> wrote:
> Does C++ check whether a pointer you're deferencing is zero? Or will it
> just segfault?
I don't remember for sure, but I think that the standard might say
something that if you access the data behind a null pointer the program
will be terminated.
At least in practice this is so in all the most common systems.
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New <dne### [at] san rr com> wrote:
> > So I say "int *x = 0;" and then later I can check that "if (x == 0) ..."?
> Yes. Note that in each case, that's technically a cast. The bit pattern
> of the pointer doesn't have to be zeros. If it's a null pointer, casting
> it to an integer gives you zero, and casting the integer 0 to a pointer
> gives you null.
> At least in C, the "NULL" macro is more commonly used to me "a pointer
> that when cast to an integer yields zero." I think C++ changed this
> when it improved the type system.
The next C++ standard will actually introduce the keyword nullptr
to better disambiguate between the integer 0 and the null pointer.
Currently if you have this:
#include <cstddef>
void foo(int);
void foo(int*);
void main()
{
foo(NULL);
}
the foo(int) function will be called (and the compiler might give you a
warning about this if it's smart enough).
With the next standard you can write:
foo(nullptr);
and the foo(int*) function will be called.
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> the foo(int) function will be called (and the compiler might give you a
> warning about this if it's smart enough).
Ah! OK. I wondered why C++ had bothered to change this, but now it makes
sense, yes.
Actually, many times I've seen NULL defined as
#define NULL ((void*)0)
I'm not sure which (if either) such a thing would match in your C++ example.
--
Darren New / San Diego, CA, USA (PST)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> I don't remember for sure, but I think that the standard might say
> something that if you access the data behind a null pointer the program
> will be terminated.
I would be surprised if running off the end of an array is undefined but
accessing the null pointer is defined. It would prevent C++ from being
standards-compliant in lots of places that don't have memory management
hardware. I wouldn't be surprised if the number of such systems actually
outnumbers the number of systems *with* memory protection, once you
start counting cell phones, microwave ovens, televisions, etc.
However, you may very well be right. I'm just guessing from
what-should-be-reasonable. :-)
> At least in practice this is so in all the most common systems.
Most common desktop systems, yes. I suspect this is more a POSIX thing
than a C++ thing, really.
--
Darren New / San Diego, CA, USA (PST)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New <dne### [at] san rr com> wrote:
> Actually, many times I've seen NULL defined as
> #define NULL ((void*)0)
> I'm not sure which (if either) such a thing would match in your C++ example.
The problem with that is that void* is not implicitly castable to any
other pointer type in C++ due to C++ having stricter implicit casting
rules than C.
You might try some clever tricks using templates and type conversion
operators, but then you will probably stumble accross problems with
method pointers and member variable pointers (which are one of the most
obscure features of C++).
'nullptr' will be a generic null pointer which is implicitly convertible
to any other pointer type.
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
On Wed, 24 Sep 2008 19:53:49 +0200, Warp <war### [at] tag povray org> wrote:
> I don't remember for sure, but I think that the standard might say
> something that if you access the data behind a null pointer the program
> will be terminated.
It does not. Dereferencing a null pointer has undefined behaviour.
> At least in practice this is so in all the most common systems.
Because it is enforced by the OS.
--
FE
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible wrote:
> My understanding is that when you create variables, they start off
> containing junk unless you initialise them (or their types have
> constructors which initialise them to something specific). Is that correct?
I may be wrong, but I believe all variables declared outside of a
function have default values.
--
For Sale: Parachute. Only used once, never opened, small.
/\ /\ /\ /
/ \/ \ u e e n / \/ a w a z
>>>>>>mue### [at] nawaz org<<<<<<
anl
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Mueen Nawaz wrote:
> I may be wrong, but I believe all variables declared outside of a
> function have default values.
More exactly, in C at least, any variables allocated statically start
with a default value of zero appropriate for their type. That includes
static variables allocated inside a function.
--
Darren New / San Diego, CA, USA (PST)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New <dne### [at] san rr com> wrote:
> Mueen Nawaz wrote:
> > I may be wrong, but I believe all variables declared outside of a
> > function have default values.
> More exactly, in C at least, any variables allocated statically start
> with a default value of zero appropriate for their type. That includes
> static variables allocated inside a function.
It would be interesting to see a quote from the C standard.
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
On Wed, 24 Sep 2008 23:51:27 +0200, Warp <war### [at] tag povray org> wrote:
> Darren New <dne### [at] san rr com> wrote:
>> More exactly, in C at least, any variables allocated statically start
>> with a default value of zero appropriate for their type. That includes
>> static variables allocated inside a function.
>
> It would be interesting to see a quote from the C standard.
How about the C++ standard?
3.6.2 §1:
"The storage for objects with static storage duration (3.7.1) shall be
zero-initialized (8.5) before any other initialization takes place."
--
FE
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> Darren New <dne### [at] san rr com> wrote:
>> Mueen Nawaz wrote:
>>> I may be wrong, but I believe all variables declared outside of a
>>> function have default values.
>
>> More exactly, in C at least, any variables allocated statically start
>> with a default value of zero appropriate for their type. That includes
>> static variables allocated inside a function.
>
> It would be interesting to see a quote from the C standard.
http://atrey.karlin.mff.cuni.cz/projekty/vrr/doc/c99.pdf
Section 6.7.8, page 126 (or sheet 138). Check rule 10.
But come on, this has been the case since K&R First Edition. :-)
--
Darren New / San Diego, CA, USA (PST)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New wrote:
> Mueen Nawaz wrote:
>> I may be wrong, but I believe all variables declared outside of a
>> function have default values.
>
> More exactly, in C at least, any variables allocated statically start
> with a default value of zero appropriate for their type. That includes
> static variables allocated inside a function.
Yes, I seem to recall that it's true for static variables as well (in
C++ - not sure about C).
--
Atheism is a non-prophet organization.
/\ /\ /\ /
/ \/ \ u e e n / \/ a w a z
>>>>>>mue### [at] nawaz org<<<<<<
anl
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Mueen Nawaz wrote:
> Yes, I seem to recall that it's true for static variables as well
> (in C++ - not sure about C).
I hedged my bets, not knowing whether statically allocated instances of
a class with a constructor invoked the constructor. I'm pretty sure it
does, but I didn't feel like trying to google it up. :-) Maybe it
initializes to zero everything before it invokes the constructor or
something. (Which I would suspect, given that it's often the OS that
does that initialization as it allocates the pages.)
--
Darren New / San Diego, CA, USA (PST)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
> More exactly, in C at least, any variables allocated statically start with
> a default value of zero appropriate for their type. That includes static
> variables allocated inside a function.
I was under the impression that global variables are initialized to zero,
but you can't trust local variables because the stack has whatever garbage
data was left on it from previously called functions.
- Slime
[ http://www.slimeland.com/ ]
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
> Does C++ check whether a pointer you're deferencing is zero? Or will it
> just segfault?
In practice it segfaults. Any time you think there's even a chance of this
happening, do
assert( ptr );
to catch it ahead of time. (This will assert that it is not 0, or NULL).
You'll save yourself some headaches.
- Slime
[ http://www.slimeland.com/ ]
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Man, I'm in the wrong time zone. You always get to answer the questions
first! =)
- Slime
[ http://www.slimeland.com/ ]
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Slime wrote:
> Man, I'm in the wrong time zone. You always get to answer the questions
> first! =)
Which timezone is that then?
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible wrote:
> (You knew there were going to be a few at some point...)
>
> I just want to make sure I've got this absolutely straight in my head.
> So... a reference is the same as a pointer, except that it has nicer
> syntax, and you cannot change where it points to?
>
> If I'm understanding this correctly, a "union" is like several structs
> with the same base address, and you can treat it was one struct or the
> other struct, and it's up to you to remember which which struct you're
> currently using it is. (I.e., the language itself provides no way to
> distinguish.)
>
> Here's a perverse question: can a union have member functions?
Yes.
> My understanding is that when you create variables, they start off
> containing junk unless you initialise them (or their types have
> constructors which initialise them to something specific). Is that correct?
Yes.
> Does C++ have a concept of a "null pointer" - i.e., a pointer that
> doesn't point to anything valid, and can be detected as such?
Yes.
> How does memory allocation work in C++? If a program fills the heap, do
> you have to explicitly *do* something to enlarge the heap, or does it
> grow automatically? Does it shrink back again after you release things,
> or do you have to request that manually?
Depends on the implementation.
Regards,
John
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Slime wrote:
>> More exactly, in C at least, any variables allocated statically start with
>> a default value of zero appropriate for their type. That includes static
>> variables allocated inside a function.
>
>
> I was under the impression that global variables are initialized to zero,
> but you can't trust local variables because the stack has whatever garbage
> data was left on it from previously called functions.
Correct. I was also pointing out that they get initialized to the type's
version of zero, whatever that might be. (I.e., pointers may not have
all zero bits in them; they get initialized to null instead.) Rarely can
you see this difference. :-)
And variables that are static but not global also get initialized.
--
Darren New / San Diego, CA, USA (PST)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New <dne### [at] san rr com> wrote:
> Correct. I was also pointing out that they get initialized to the type's
> version of zero, whatever that might be. (I.e., pointers may not have
> all zero bits in them; they get initialized to null instead.) Rarely can
> you see this difference. :-)
Actually it's possible to invoke the "default initialization" for any
type at any point in C++. For example if you do this:
int i = int();
the 'i' variable will be default-initialized with the "zero" value for
the type in question (which, in this case, is the integer 0).
One might ask what's the point. It's actually useful when you don't
know what the type actually is. This happens eg. with templates. You
could have, for example, this:
template<typename Type>
void foo()
{
Type i = Type(); // Default-initialize i, even if it's a basic type
...
}
Although mostly it's useful in situations where you want to create a
default-initialized temporary, for example in code like this:
someVector.push_back(Type());
That will work even if 'Type' is an int, a double or a pointer.
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
> Which timezone is that then?
PST. (California.)
- Slime
[ http://www.slimeland.com/ ]
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Slime wrote:
>> Which timezone is that then?
>
> PST. (California.)
You're Californian?
Wow... suddenly a whole lot of POV-Ray stuff makes way more sense... ;-)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Copy...constructor...? x_x
Heh. And I thought figurating out the difference between a const pointer
and a pointer to a const was hard!
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible wrote:
> Copy...constructor...? x_x
Pointers to members?
OK, maybe I should stop reading now. :-/
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible <voi### [at] dev null> wrote:
> Copy...constructor...? x_x
Usually you don't need copy constructors unless you have pointers as
member variables of your class and you explicitly allocate memory to
them with 'new'. But we don't do that, do we? ;)
If you want a quick crash course on copy constructing when the class
allocates memory explicitly, check this:
http://warp.povusers.org/c++test/
(There are actually a few other situations where a copy constructor is
mandatory for a class to work properly, but they are slightly advanced
stuff.)
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible <voi### [at] dev null> wrote:
> Pointers to members?
You don't need them.
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> Invisible <voi### [at] dev null> wrote:
>> Pointers to members?
>
> You don't need them.
That's what I was pretty much hoping, yeah.
Looks like it would only be useful for some pretty obscure situations...
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> Invisible <voi### [at] dev null> wrote:
>> Copy...constructor...? x_x
>
> Usually you don't need copy constructors unless you have pointers as
> member variables of your class and you explicitly allocate memory to
> them with 'new'. But we don't do that, do we? ;)
Heh. I get the impression that most of the stuff I'm reading about now
is stuff that "you won't normally need". ;-)
(E.g., apparently you can overload the "->" operator... GAH! >_< OK, I
am *so* not trying that out!)
Anyway, the main reason I haven't written a Third C++ Program yet is
that I'm trying to think of something I actually want to write that's
implementable without automatic memory management...
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible <voi### [at] dev null> wrote:
> Warp wrote:
> > Invisible <voi### [at] dev null> wrote:
> >> Pointers to members?
> >
> > You don't need them.
> That's what I was pretty much hoping, yeah.
> Looks like it would only be useful for some pretty obscure situations...
They are useful in certain situations, but those situations are so rare
and usually so advanced, that even very experienced C++ programmers basically
never need them.
I once created a command-line parameter interpreter which was used like
this (extremely simplified):
class MyCLI: public CommandLineInterpreter
{
void inputFile() { ... }
public:
MyCLI()
{
// registerCLParameter() is a function in the base class.
registerCLParameter("input", &inputFile);
}
};
Basically this meant that when the interpreter encountered the command-line
parameter "-input", it would call the 'inputFile()' method I defined above.
This uses method pointers.
(The actual implementation is quite complicated because there are some
issues about a base class calling a derived class method through a method
pointer, but with template magic it's possible to do this portably and
safely.)
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible <voi### [at] dev null> wrote:
> Warp wrote:
> > Invisible <voi### [at] dev null> wrote:
> >> Copy...constructor...? x_x
> >
> > Usually you don't need copy constructors unless you have pointers as
> > member variables of your class and you explicitly allocate memory to
> > them with 'new'. But we don't do that, do we? ;)
> Heh. I get the impression that most of the stuff I'm reading about now
> is stuff that "you won't normally need". ;-)
It's not like you don't need copy constructors (and copy assignment).
It's just that a beginner doesn't usually need them. When you start needing
copy constructors, your code will be a bit more advanced.
> (E.g., apparently you can overload the "->" operator... GAH! >_< OK, I
> am *so* not trying that out!)
You can overload almost any operator, including 'new' (it's considered
an operator in C++) and the prefix-&.
I think the only operator you can't overload is the dot operator.
> Anyway, the main reason I haven't written a Third C++ Program yet is
> that I'm trying to think of something I actually want to write that's
> implementable without automatic memory management...
Hmm, is that sentence correct? Everything is implementable without
automatic memory management. Perhaps you meant something else?-)
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
>> Heh. I get the impression that most of the stuff I'm reading about now
>> is stuff that "you won't normally need". ;-)
>
> It's not like you don't need copy constructors (and copy assignment).
> It's just that a beginner doesn't usually need them. When you start needing
> copy constructors, your code will be a bit more advanced.
Well, yeah. And *I* am unlikely to be writing anything "advanced" any
time soon! ;-)
>> (E.g., apparently you can overload the "->" operator... GAH! >_< OK, I
>> am *so* not trying that out!)
>
> You can overload almost any operator, including 'new' (it's considered
> an operator in C++) and the prefix-&.
>
> I think the only operator you can't overload is the dot operator.
And .* (apparently).
Also, unlike Haskell, you apparently can't make up new operators of your
own, just overload the ones that already exist.
>> Anyway, the main reason I haven't written a Third C++ Program yet is
>> that I'm trying to think of something I actually want to write that's
>> implementable without automatic memory management...
>
> Hmm, is that sentence correct? Everything is implementable without
> automatic memory management. Perhaps you meant something else?-)
Well, yeah, but it's a touch harder to implement heap-allocated data in
such a way that your program doesn't leak like a sieve. ;-)
[I'm actually surprised that using std::vector doesn't do this already...]
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible <voi### [at] dev null> wrote:
> Also, unlike Haskell, you apparently can't make up new operators of your
> own, just overload the ones that already exist.
Aren't C++ compilers already stressed enough? Think about all the problems
they would have with user-defined operators, with their own precedence
rules, ambiguous situations, etc... :P
> Well, yeah, but it's a touch harder to implement heap-allocated data in
> such a way that your program doesn't leak like a sieve. ;-)
You usually use the STL data containers for dynamically allocated
memory, and if what you need is to allocate a single object, you can
use a smart pointer (I posted in the other group an URL to one smart
pointer implementation I have made).
> [I'm actually surprised that using std::vector doesn't do this already...]
Doesn't do what?
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
>> Also, unlike Haskell, you apparently can't make up new operators of your
>> own, just overload the ones that already exist.
>
> Aren't C++ compilers already stressed enough? Think about all the problems
> they would have with user-defined operators, with their own precedence
> rules, ambiguous situations, etc... :P
Heh, yeah... I can see that. ;-)
>> Well, yeah, but it's a touch harder to implement heap-allocated data in
>> such a way that your program doesn't leak like a sieve. ;-)
>
> You usually use the STL data containers for dynamically allocated
> memory, and if what you need is to allocate a single object, you can
> use a smart pointer.
Fair enough.
>> [I'm actually surprised that using std::vector doesn't do this already...]
>
> Doesn't do what?
Leak like a sieve! ;-)
I've never actually seen a programming environment with manual memory
management *and* dynamically resizable collections. The two are usually
muturally exclusive.
Then again, I'm not really sure what the story is if you try to put
user-defined data types into a vector...
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible wrote:
>
> (E.g., apparently you can overload the "->" operator... GAH! >_< OK, I
> am *so* not trying that out!)
>
Useful for the "Smart Pointer" pattern. The autogen stuff for COM uses
these a lot.
--
~Mike
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible <voi### [at] dev null> wrote:
> >> [I'm actually surprised that using std::vector doesn't do this already...]
> >
> > Doesn't do what?
> Leak like a sieve! ;-)
The class constructors, assignment and destructor help in automatizing
the internal memory management of the vector.
You can write your own dynamic data container as a class in the exact
same way as std::vector and the other STL containers, which will be safe
and will automatically manage its memory.
And not only memory. There are also other resources which can be
automatically managed with classes. Consider this:
void foo()
{
std::ofstream os("outfile.txt");
os << "Hello\n";
bar();
os << "there.\n";
}
Note that nowhere is the file actually explicitly *closed*. However,
no open file handles are leaked because it gets closed automatically
because the std::ofstream class handles this resource.
This is even so even if the function is exited abnormally. For example,
assume that the bar() call throws an exception. If that happens, the
function will be exited immediately (before the "there.\n" string is
written to the file). This is "unexpected" and we didn't take that
possibility into account. However, it doesn't matter: The file will
still be closed and thus no resource leak happens.
Unless I'm completely mistaken, this is not something you can achieve
in Java. (In Java you have to close files explicitly and catch all
possible exceptions which might otherwise bypass that closing.)
> I've never actually seen a programming environment with manual memory
> management *and* dynamically resizable collections. The two are usually
> muturally exclusive.
Well, it's not like *all* resources in C++ are managed manually.
More precisely, stack-allocated objects are managed automatically. Which
is exactly the reason why automatic management heap-allocated objects
becomes possible through these stack-allocated objects.
> Then again, I'm not really sure what the story is if you try to put
> user-defined data types into a vector...
If the user-defined type doesn't allocate memory in itself, or if it
does but manages it properly, there shouldn't be any problems.
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Mike Raiford <"m[raiford]!at"@gmail.com> wrote:
> Invisible wrote:
> > (E.g., apparently you can overload the "->" operator... GAH! >_< OK, I
> > am *so* not trying that out!)
> >
> Useful for the "Smart Pointer" pattern. The autogen stuff for COM uses
> these a lot.
Also used with iterators. (An iterator is an object which behaves
like a pointer.)
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> The class constructors, assignment and destructor help in automatizing
> the internal memory management of the vector.
>
> You can write your own dynamic data container as a class in the exact
> same way as std::vector and the other STL containers, which will be safe
> and will automatically manage its memory.
But presumable you'd need to know what you're doing first. ;-)
> And not only memory. There are also other resources which can be
> automatically managed with classes.
Mmm, that's nice.
> Unless I'm completely mistaken, this is not something you can achieve
> in Java. (In Java you have to close files explicitly and catch all
> possible exceptions which might otherwise bypass that closing.)
Actually, for reasons beyond my comprehension, if a Haskell program
halts abnormally, all files are closed, but not necessarily *flushed*.
Like, WTF? *Why?* Anyway, basically you have to write some code to catch
the exception and close the file before rethrowing it. It's an extra 3
lines of code, but you still have to remember to type them...
>> I've never actually seen a programming environment with manual memory
>> management *and* dynamically resizable collections. The two are usually
>> muturally exclusive.
>
> Well, it's not like *all* resources in C++ are managed manually.
> More precisely, stack-allocated objects are managed automatically. Which
> is exactly the reason why automatic management heap-allocated objects
> becomes possible through these stack-allocated objects.
Indeed. I've not seen this in any other OO language.
>> Then again, I'm not really sure what the story is if you try to put
>> user-defined data types into a vector...
>
> If the user-defined type doesn't allocate memory in itself, or if it
> does but manages it properly, there shouldn't be any problems.
Sounds good to me! ;-)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible wrote:
> Looks like it would only be useful for some pretty obscure situations...
Really? They're useful all the time in C#. Like, every time you have a
callback function you register with the GUI, or every time in Java where
you'd have to create an anonymous inner class or something. Pointers to
members are the OO mechanism corresponding to closures.
You have a window representing an object. You want to be notified
whenever the mouse moves over the window. How do you tell the window
manager that?
--
Darren New / San Diego, CA, USA (PST)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> Unless I'm completely mistaken, this is not something you can achieve
> in Java. (In Java you have to close files explicitly and catch all
> possible exceptions which might otherwise bypass that closing.)
The destructor will close the file when the GC collects the object, but
that might be several seconds later. And it might not run if you exit
the program before the GC runs, but that's true of C++ also. So it's not
quite as nicely deterministic, but it still happens eventually.
--
Darren New / San Diego, CA, USA (PST)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible wrote:
> Actually, for reasons beyond my comprehension, if a Haskell program
> halts abnormally, all files are closed, but not necessarily *flushed*.
Because it's Haskell that flushes the buffers to the file, but it's the
OS that closes the file. If you run it on (say) an Amiga, it won't close
the files, either. Apparently Haskell isn't writing directly to the
files, but to Haskell-managed buffers. Same thing happens in C with stdio.
--
Darren New / San Diego, CA, USA (PST)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New wrote:
>
> The destructor will close the file when the GC collects the object, but
> that might be several seconds later. And it might not run if you exit
> the program before the GC runs, but that's true of C++ also. So it's not
> quite as nicely deterministic, but it still happens eventually.
>
C# has the same issue. You can sort of work around it with the using
statement, which will call Dispose on an IDisposable object, which, in
turn, closes the file.
--
~Mike
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Mike Raiford wrote:
> Darren New wrote:
>
>>
>> The destructor will close the file when the GC collects the object,
>> but that might be several seconds later. And it might not run if you
>> exit the program before the GC runs, but that's true of C++ also. So
>> it's not quite as nicely deterministic, but it still happens eventually.
>>
>
> C# has the same issue. You can sort of work around it with the using
> statement, which will call Dispose on an IDisposable object, which, in
> turn, closes the file.
Yep. Of course, it's really not a problem in a system where the kernel
participates in the GC, like Singularity does.
And, really, memory is a huge percentage of the resources you manage, so
the small bit of "real" resources you have to handle manually is usually
not much of a problem. Indeed, only once did I have code sufficiently
convoluted and error-prone that I had a resource leak of this type in
Tcl. And even then, it's because I wrote the code poorly and instead of
(say) wrapping the allocation and use in a procedure call, I tried to
handle it all inline.
--
Darren New / San Diego, CA, USA (PST)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New wrote:
> Invisible wrote:
>> Actually, for reasons beyond my comprehension, if a Haskell program
>> halts abnormally, all files are closed, but not necessarily *flushed*.
>
> Because it's Haskell that flushes the buffers to the file, but it's the
> OS that closes the file. If you run it on (say) an Amiga, it won't close
> the files, either. Apparently Haskell isn't writing directly to the
> files, but to Haskell-managed buffers. Same thing happens in C with stdio.
Yeah, but if the Haskell runtime has code to handle printing out a
human-readable error message on an unhandled exception, why can't it
also run some finalisers? This is pretty basic stuff!
--
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
On Fri, 26 Sep 2008 16:30:35 +0200, Invisible <voi### [at] dev null> wrote:
>> I think the only operator you can't overload is the dot operator.
>
> And .* (apparently).
:: and ?: cannot be overloaded either.
--
FE
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New <dne### [at] san rr com> wrote:
> Invisible wrote:
> > Looks like it would only be useful for some pretty obscure situations...
> Really? They're useful all the time in C#. Like, every time you have a
> callback function you register with the GUI, or every time in Java where
> you'd have to create an anonymous inner class or something. Pointers to
> members are the OO mechanism corresponding to closures.
> You have a window representing an object. You want to be notified
> whenever the mouse moves over the window. How do you tell the window
> manager that?
Isn't this usually handled with callback interfaces (in OO languages)
rather than function pointers?
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Fredrik Eriksson wrote:
> On Fri, 26 Sep 2008 16:30:35 +0200, Invisible <voi### [at] dev null> wrote:
>>> I think the only operator you can't overload is the dot operator.
>>
>> And .* (apparently).
>
> :: and ?: cannot be overloaded either.
That seems logical...
I bet you can't overload ";", can you? In Haskell, you can. >:-D
--
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |