POV-Ray : Newsgroups : povray.off-topic : C++ questions : Re: C++ questions Server Time
7 Sep 2024 07:24:30 EDT (-0400)
  Re: C++ questions  
From: Warp
Date: 30 Sep 2008 11:37:29
Message: <48e247b9@news.povray.org>
Invisible <voi### [at] devnull> wrote:
> Hmm, so vectors seem to be able to do some pretty death-defying stuff! 
> They're variable size, but they manage their memory automatically.

> Now in a GC language, you can just pass anything anywhere. Usually in a 
> language with manual memory management you have to be extremely careful 
> about doing that.

> However, vectors seem to make this surprisingly safe. Indeed, it appears 
> that you can pass a vector in any way that you could pass something like 
> an integer, and it will just do The Right Thing(tm). The only difference 
> is that throwing a large vector around by value probably isn't a good idea.

> Is that about right?

  That's the whole idea in C++ class design. If you write a class which is
not safe to use like that, then your design is bad.

  C++ classes have been designed to allow you to do that. As long as
you just create local instances of them and pass them by value (in other
words, as long as you don't use the keyword 'new' nor store pointers which
last longer than the object), if the class has been implemented properly
it's completely safe. (Ok, there are some exceptions, but basically.)

  It would be perfectly possible to implement a dynamic vector class which
has all the properties as std::vector, and which is efficient to pass by
value. The vector class could basically work like a reference-counted
handle to the array (in which case all the copies share the same array).
Or it could use the copy-on-write mechanism (in which case each copy has
its own array, but it's still very efficient to pass copies around).

  The reason why std::vector doesn't implement copy-on-write is that it
would add overhead to the []-indexing, which is usually something people
don't want. However, if you don't mind that overhead, or it's enough for
all the copies to share the same array, then you can implement your own
dynamic vector which uses reference counting and thus becomes much more
efficient to pass around by value.

  The nice thing about this is that whether copying the vector object
causes a deep-copy of the array, whether it's reference-counted, or
whether it uses copy-on-write, the interface doesn't change in any way.
In other words, the internal implementation is completely transparent and
its usage is exactly the same regardless.

> Here's another question: Suppose you have a function that's supposed to 
> create a new vector and return it to the caller. What's the best way to 
> do that?

> Obviously the ideal thing to do would be to return a reference. However, 
> if I create a vector in an auto variable, presumably when the function 
> returns that variable will vanish, making the reference to it unusable. 
> (If I'm understanding how this works.)

> I guess if I return it by value the problem goes away. But that doesn't 
> seem terribly efficient.

  Actually if you have a function like:

    std::vector<int> createVector(whatever) { ... }

and then call it like:

    std::vector<int> myVector = createVector(whatever);

the compiler will most probably be able to optimize the copying away.
Basically the 'createVector()' function will build its return value right
onto that 'myVector' variable (rather than building a local copy which it
then returns by value).

  Of course there are limits to this. For example, if you have something
like this:

    std::vector<int> myVector;
    // ...some code using myVector here...
    myVector = createVector(whatever);

then the compiler has no choice: It must build the return value of
'createVector()' into a temporary and then copy it to 'myVector'.

  One common idiom is for the function to take the vector as reference:

    void createVector(whatever, std::vector<int>& result) { ... }

and then you give your vector as parameter, and the function will then
add the data to it.

  Btw, there's a trick to avoid the copying of that temporary in the first
case:

    std::vector<int> myVector;
    // ...some code using myVector here...
    std::vector<int> tempVector = createVector(whatever);
    myVector.swap(tempVector);

  What this does is that the result of 'createVector' is built onto
'tempVector', and then its contents swapped with 'myVector'. Swapping of
vectors is an O(1) operation and avoids the needless copying.)

-- 
                                                          - Warp


Post a reply to this message

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