POV-Ray : Newsgroups : povray.off-topic : New NearInfinity demo up Server Time
6 Sep 2024 21:23:31 EDT (-0400)
  New NearInfinity demo up (Message 21 to 25 of 25)  
<<< Previous 10 Messages Goto Initial 10 Messages
From: Darren New
Subject: Re: New NearInfinity demo up
Date: 16 Dec 2008 15:43:10
Message: <494812de$1@news.povray.org>
Warp wrote:
> Darren New <dne### [at] sanrrcom> wrote:
>>>   The temporary given as parameter is created only once, not 64 times.
> 
>> So the declaration is essentially hoisted from out of the loop? Makes sense.
> 
>   Ok, it may be possible that it is created in each loop, depending on how
> you are creating it, so I may have exaggerated that bit, and it may indeed
> be created 64 times.

I would think if the arguments are different each time, the constructor at 
least would have to be called, even if it's overwriting the previous memory 
locations. (I.e., if the compiler allocated the space once on the stack or 
even in static memory.) And if the compiler can't tell the class's 
destructor doesn't do something like calling 'destroy', it can't just 
overwrite the constructed value without destructing it first?

>   You could manually optimize it and create it only once outside the loops,
> to make sure. (If, for example, each sprite is otherwise identical but with
> different coordinates, you could simply change the coordinates and push it
> into the vector.)

Yep.

>   OTOH in this case it probably doesn't matter.

Yep.

>   Copy constructors are called, for example, when you pass an object to
> a function by value.

Good to know. Thanks!  Still wading thru the C++ manuals and tutorials here.

>   Actually it is perfectly possible to construct into an array element
> directly. (A programmer can do that himself by using so-called placement
> new.)

Sure. I was speaking of this particular bit of code, tho.

>   Whether or not the compiler is smart enough to optimize it like that
> is another question.

OK.

>> And 
>> wouldn't it have to call the destructor on the temporary 64 times after it 
>> was copied (assuming it has a destructor)?
> 
>   If the temporary is created 64 times, then it will be destroyed 64 times
> as well, of course.

OK. So you were assuming a trivial destructor? I'm just trying to learn.

>   As I said, you may be right in that the temporary is created 64 times,
> though. You could hand-optimize it by creating it once outside the loops.

I would bet that it's easier for the compiler to create the temporary only 
once than it is for the compiler to know it can call the constructor on the 
array elements in std::vector without any temporary needed at all. :-)

-- 
   Darren New, San Diego CA, USA (PST)
   The NFL should go international. I'd pay to
   see the Detroit Lions vs the Roman Catholics.


Post a reply to this message

From: Warp
Subject: Re: New NearInfinity demo up
Date: 16 Dec 2008 16:31:01
Message: <49481e15@news.povray.org>
Darren New <dne### [at] sanrrcom> wrote:
> >   Copy constructors are called, for example, when you pass an object to
> > a function by value.

> Good to know. Thanks!  Still wading thru the C++ manuals and tutorials here.

  Copy constructors and assignment operators are important to know in C++
when designing classes.

  Usually when your class only has basic types and managed classes as
members, you don't need to create a copy constructor nor assignment operator
for your class. The default ones generated by the compiler will usually
suffice. (The default ones simply copy/assign each member of the parameter
to each member of this.)

  For example:

class MyClass
{
    int x, y; // basic types
    std::string name; // managed class

 public:
    // No need to write your own copy constructor / assignment operator
    // here because the compiler-generated ones suffice.
    ...
};

  (I think the term "managed" is not generally used in pure C++, but I'll
use that term because I can't think of any better one. Not to be confused
with managed classes in .NET; I'm not talking about those at all. With
"managed" I mean a class which may allocate memory inside itself, but is
well-behaved and can be safely copied and assigned around without worries.
std::string and the STL containers are examples.)

  Problems happen when your class has, for example, raw pointers to memory
it has allocated, or other similar resources. Example:

class MyClass
{
    int* array;

 public:
    MyClass(int size)
    {
        array = new int[size];
    }

    ~MyClass() { delete[] array; }

    // If now you don't implement a copy constructor / assignment operator
    // you will have a problem!
};

  How to solve the problem depends on how you want your class to behave.

  By far the easiest (and most common) solution is to simply forbid copying
and assignment of your class. This happens by declaring the copy constructor
and assignment operator in the private part of the class and not implementing
them. Problem solved. Of course now you can't copy nor assign instances of
your class (nor can you use them in STL containers), but in many cases you
don't need to. This is very typical for classes which you instantiate only
once during the execution of the program.

  What forbidding those functionalities does is prevent accidents, so it's
a good custom, even if you are not intending to copy/assign the class around.

  Sometimes you do want to copy/assign instances of your class, though.
In that case you have to decide whether the copies should share the data
or deep-copy it. If deep-copying is enough, then by far the easiest solution
is replacing your array with a std::vector, and consequently you don't need
to write any copy constructor / assignment operator. If you want to share,
then you could use the smart pointers offered by the Boost library. (The
current C++ standard doesn't yet offer such smart pointers, except for
auto_ptr, which cannot be used for sharing data.)

  Of course this is good only if your data is an array. If your dynamic data
has a more complex geometry, it becomes a bit more complicated.

  Also the data might not be memory at all. For example this presents the
exact same problem:

class MyClass
{
    std::FILE* inputFile;

 public:
    MyClass(): inputFile(0) {}
    ~MyClass()
    {
        if(inputFile) std::fclose(inputFile);
    }

    bool openFile(const char* filename)
    {
        if(inputFile) std::fclose(inputFile);
        return (inputFile = std::fopen(filename, "rb"));
    }

    ...
};

  The data is not memory, but if you copy/assign instances of this class,
you'll get a problem (you may access or close a closed file).

  A more subtle example:

class MyClass
{
    std::list<Node> nodes;
    std::list<Node>::iterator currentNode;
    ...
};

  Assume 'currentNode' points to some node in the list, or to nodes.end().
If this class doesn't have a proper copy constructor / assignment operator
and you copy instances of it, you'll get problems.

  I suppose the morale of this long text is: If you stick to basic types
and managed classes (as I call them) as far as possible, you'll avoid
problems. Pointers and iterators as members are often problematic.

  (Note that sometimes you might want to forbid copying/assignment even
if the compiler-generated ones were safe. This may be the case eg. if
the copying would be a very heavy operation, such as if you have huge
vectors as member variables.)

-- 
                                                          - Warp


Post a reply to this message

From: Nicolas Alvarez
Subject: Re: New NearInfinity demo up
Date: 16 Dec 2008 17:21:31
Message: <494829eb@news.povray.org>
Warp wrote:
>   By far the easiest (and most common) solution is to simply forbid
>   copying
> and assignment of your class. This happens by declaring the copy
> constructor and assignment operator in the private part of the class and
> not implementing them. Problem solved. Of course now you can't copy nor
> assign instances of your class (nor can you use them in STL containers),
> but in many cases you don't need to. This is very typical for classes
> which you instantiate only once during the execution of the program.
> 
>   What forbidding those functionalities does is prevent accidents, so it's
> a good custom, even if you are not intending to copy/assign the class
> around.
> 
>   Sometimes you do want to copy/assign instances of your class, though.
> In that case you have to decide whether the copies should share the data
> or deep-copy it. If deep-copying is enough, then by far the easiest
> solution is replacing your array with a std::vector, and consequently you
> don't need to write any copy constructor / assignment operator. If you
> want to share, then you could use the smart pointers offered by the Boost
> library. (The current C++ standard doesn't yet offer such smart pointers,
> except for auto_ptr, which cannot be used for sharing data.)

More info on this is available on Warp's website :)

http://warp.povusers.org/c++test/


Post a reply to this message

From: Darren New
Subject: Re: New NearInfinity demo up
Date: 16 Dec 2008 18:53:09
Message: <49483f65$1@news.povray.org>
Warp wrote:
>   Copy constructors and assignment operators are important to know in C++
> when designing classes.

Yes. So far, that's really the only part that doesn't seem pretty obvious 
just skimming thru tutorials. Hence the wading in seriously.

>   (I think the term "managed" is not generally used in pure C++, but I'll
> use that term because I can't think of any better one.

Yeah. I wonder if MS actually defines the term "managed" clearly. :-) Other 
than "that stuff .NET does for you."


Thanks. I'll come back and re-read this again when I get past the chapter 
that talks about such stuff explicitly.


-- 
   Darren New, San Diego CA, USA (PST)
   The NFL should go international. I'd pay to
   see the Detroit Lions vs the Roman Catholics.


Post a reply to this message

From: scott
Subject: Re: New NearInfinity demo up
Date: 17 Dec 2008 03:46:32
Message: <4948bc68@news.povray.org>
> I see. The array itself was not dynamic, so there was no reason to delete 
> it. Despite my limited knowledge of the subject, I managed to do the right 
> thing by deleting them individually... They were deleted in the same 
> manner as they were created. There's more to this issue I need to explore, 
> and I'm not ashamed to admit it ;)
>
> Who's going to trust my programs, now that my ignorance is known? I could 
> always provide the source...

Hehe I had something similar where I had forgotten to type the "()" after a 
release call on a texture object (this is DirectX).  For some reason the 
compiler though that:

texture1->Release;

was a perfectly fine statement, but of course it wasn't calling the release 
function to free up the memory.  It took me ages to track this one down, 
because quickly reading that line you don't notice the () missing, and it 
just caused random crashes occasionally on exit.

Took me a while to figure out the whole delete [] palaver too.

Oh well, you live and learn :-)


Post a reply to this message

<<< Previous 10 Messages Goto Initial 10 Messages

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