POV-Ray : Newsgroups : povray.off-topic : C++ questions Server Time
7 Sep 2024 17:14:57 EDT (-0400)
  C++ questions (Message 1 to 10 of 123)  
Goto Latest 10 Messages Next 10 Messages >>>
From: Invisible
Subject: C++ questions
Date: 24 Sep 2008 10:17:22
Message: <48da4bf2$1@news.povray.org>
(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

From: Warp
Subject: Re: C++ questions
Date: 24 Sep 2008 11:23:59
Message: <48da5b8e@news.povray.org>
Invisible <voi### [at] devnull> 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

From: Invisible
Subject: Re: C++ questions
Date: 24 Sep 2008 11:36:44
Message: <48da5e8c@news.povray.org>
Warp wrote:
> Invisible <voi### [at] devnull> 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

From: Darren New
Subject: Re: C++ questions
Date: 24 Sep 2008 12:19:55
Message: <48da68ab$1@news.povray.org>
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

From: Warp
Subject: Re: C++ questions
Date: 24 Sep 2008 13:53:49
Message: <48da7ead@news.povray.org>
Invisible <voi### [at] devnull> 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

From: Warp
Subject: Re: C++ questions
Date: 24 Sep 2008 13:57:46
Message: <48da7f9a@news.povray.org>
Darren New <dne### [at] sanrrcom> 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

From: Darren New
Subject: Re: C++ questions
Date: 24 Sep 2008 14:02:49
Message: <48da80c9$1@news.povray.org>
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

From: Darren New
Subject: Re: C++ questions
Date: 24 Sep 2008 14:06:30
Message: <48da81a6@news.povray.org>
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

From: Warp
Subject: Re: C++ questions
Date: 24 Sep 2008 14:08:20
Message: <48da8214@news.povray.org>
Darren New <dne### [at] sanrrcom> 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

From: Fredrik Eriksson
Subject: Re: C++ questions
Date: 24 Sep 2008 14:25:39
Message: <op.uhzz41oj7bxctx@e6600>
On Wed, 24 Sep 2008 19:53:49 +0200, Warp <war### [at] tagpovrayorg> 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

Goto Latest 10 Messages Next 10 Messages >>>

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