Sign in to follow this  
Decrius

C++, use references without copying

Recommended Posts

I have a class, called GUI, which dynamically allocates an Container object. Via a function I would then like to pass the pointer/reference to the Container object, so the user can fill it. I don't see how I can easily do this, mainly because I want the code the look best at the user end and don't want to copy data rather then pointers. Code:
#include "opengui/gui.h"
#include <iostream>

namespace OpenGUI
{
    class Container
    {
    public:
        Container(int x = 0, int y = 0, int w = 0, int h = 0);
        ~Container();

        Container &operator[] (int i);
        Container &operator[] (std::string name);       

    private:
        std::vector<Container *> containers;
        std::map<std::string, int> names;   // points to vector
    };
}

namespace OpenGUI
{
    class OpenGUI
    {
    public:
        OpenGUI(int x, int y, int w, int h);

        void initialise();
        void initialise(int x, int y, int w, int h);

        Container &get_container();

    private:
        Container *container;
    };
}

namespace OpenGUI
{    ///////////////////////////////////////////////////////////////////////////////

    OpenGUI::OpenGUI(int x, int y, int w, int h)
    {
        initialise(x, y, w, h);
    }

    void OpenGUI::initialise(int x, int y, int w, int h)
    {
        container = new Container(x, y, w, h);
    }
    ///////////////////////////////////////////////////////////////////////////////

    Container &OpenGUI::get_container()
    {
        std::cerr << "->" << container << "<-";
        return *container;
    }
    ///////////////////////////////////////////////////////////////////////////////
}

void main()
{
    OpenGUI::OpenGUI gui(0, 0, 800, 600);
    OpenGUI::Container main = gui.get_container(); // slow (copies value rather then address
    std::cerr << "->" << &main << "<-";

    main["window"].function(data, whatever);
}

Outputs 2 different addresses ofcourse, since I copy the data to a new address. What would be a good solution in this case? I can't seem to find any. Either I use pointers, which would make the code look awfull and more difficult to handle. Is there a way to do this? Any ideas? Thanks.

Share this post


Link to post
Share on other sites
iam not sure if i understood your Problem correctly:

you do not want to copy by value in this line right?


OpenGUI::Container main = gui.get_container(); // slow (copies value rather then address



It copies the values because main is an object (on the stack) and not a reference.
(the standard =operator copies by value just like the default copy
constructor)

This should work: (AFAIK)

OpenGUI::Container& main = gui.get_container();

Share this post


Link to post
Share on other sites
get_container() could return via an output parameter rather than a return value, e.g


bool get_container(Container& containerOut)
{
if(mContainer != NULL)
{
containerOut = mContainer;
return true;
}
return false;
}




Alternatively, declare 'main' as a reference. (and maybe call it something other than main while you're at it)

e.g


void main()
{
OpenGUI::OpenGUI gui(0, 0, 800, 600)
OpenGUI::Container& guiMain = gui.get_container();
// blah
}




The pointer method and the output parameter method have the advantage that you can test the validity of the return value for get_container and handle it nicely. For the return by reference method, you've got no option but to handle an exception.

Of course, in the code you've presented so far, it will never be NULL, but it's difficult to know how the code will be used in the future. And there are some cases where there really is an absolute need to be able to check that value.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sandman
get_container() could return via an output parameter rather than a return value, e.g

*** Source Snippet Removed ***


Huh? That would create a copy as well. You cannot change the destination of a reference once created.

I think Noobico has pinpointed exactly what the original poster's mistake was.

-Markus-

Share this post


Link to post
Share on other sites
Quote:
Original post by Noobico
This should work: (AFAIK)
*** Source Snippet Removed ***


That works, thanks :).

Quote:
And there are some cases where there really is an absolute need to be able to check that value.


I would like my library to be as usefull as possible, could you give me an example of such situation? I don't fully understand it.

I try to keep all dynamic allocations and pointer handlings transparant to the user. This keeps the user code clean and easy :)

Thanks guys.

Share this post


Link to post
Share on other sites
Quote:
Original post by Cygon
Huh? That would create a copy as well. You cannot change the destination of a reference once created.


Erk, of course you're right. I don't know what I was thinking. I blame too many late nights of C# coding.

Quote:

I would like my library to be as usefull as possible, could you give me an example of such situation? I don't fully understand it.


Basically, anywhere where you're returning something that might legitimately be NULL.

For example, suppose you wanted to defer allocation of the container to some later time, and remove the initialize call from the constructor. Suddenly it becomes possible to call get_container() without having allocated one.

If you're returning a reference, you'll get thrown an exception. In some cases, this may be what you want, but there are plenty of cases where it might be a bit drastic. Throwing exceptions inside destructors is never a good idea, for example.

If you return a pointer, you can check it for null without invoking the whole exception handling stack unwinding process.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this