Sign in to follow this  
leidegren

C++ pass-by-reference and factory functions

Recommended Posts

I've created a factory function to create an object for me, this object is exposed by an interface ISomething.
void create_something( ISomething& something )
{
  something = *new CSomething();
}
I'm uncertain to what's happening at this point. As I understand it, I'm creating the new instance of CSomething, then dereferencing that pointer to assign to the something reference. The step of derferencing for assignment, how is this really done? Is it okay, or is there a better way of really emphizaing the pass-by-result parameter passing. I'm curious to what type of scemantic will be used. I'm actually concerned that it could take on the reference of a copy of the newly allocated object.

Share this post


Link to post
Share on other sites
This doesn't work. You're passing a reference to an existing object A. Then, you allocate a new object, B. Then, you use ISomething::operator= to somehow copy a part of B into A (and the operator does not take into account the parts that are not in ISomething, which means that usually it will either cause a compiler error or not copy anything at all). Then, you leak the memory for object B, which you never deallocate. That's it.

If your intent is to create a new object, return it by smart pointer. For shared ownership:
boost::shared_ptr<ISomething> create_something()
{
return boost::shared_ptr<ISomething>(new CSomething);
}


For simple ownership:
std::auto_ptr<ISomething> create_something()
{
return std::auto_ptr<ISomething>(new CSomething);
}

Share this post


Link to post
Share on other sites
The code you wrote is very bad. Here is what happens.


// Suppose you do this:
ISomething foo;
create_something(foo);

// Since you passed-by-reference, the function call is equivalent to:
foo = *new CSomething();

// new CSomething() dynamically allocates memory for a CSomething and returns a
// pointer to it. This dynamically allocated memory can *only* be freed by
// calling delete on the pointer returned. Unless your "factory function"
// expects the users to call delete &foo, you are going to leak memory.


The new operator should only ever return into a pointer. Just remember that every new needs to be followed up with a delete before your program ends.

Share this post


Link to post
Share on other sites
I was thinking of something along the line
class CSomething
{
public:
int x;
};

void create_something( CSomething& something )
{
something = *new CSomething();
something.x = 1;
}

int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
CSomething& something;
create_something(something);
return 0;
}
And this doesn't work since a reference cannot be uninitialized.

Are the any particular great uses for reference types? I have a couple in mind, but what would you generally use them for? How do they augment normal pointers?

Share this post


Link to post
Share on other sites
Quote:
Original post by leidegren
I have a couple in mind, but what would you generally use them for? How do they augment normal pointers?


Pointers can be null, references cannot. Therefore, you should use references when you need an object to always be present, and pointers when you need the possibility for an object to be absent.

Using a reference when the object might be absent is impossible. Using a pointer where an object must always be present forces you to assert(ptr) every other line.

Share this post


Link to post
Share on other sites
Quote:
Original post by leidegren
I was thinking of something along the line
void create_something( CSomething& something )
{
something = *new CSomething();
something.x = 1;
}

int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
CSomething& something;
create_something(something);
return 0;
}

The big problem is that you can't assign a reference as if it is a pointer. This works better (but I would simply have the function return a pointer instead, or use a smart pointer as ToohrVyk wrote):
    void create_something( CSomething*& something )
{
something = new CSomething();
something->x = 1;
}

int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
CSomething* something;
create_something(something);
delete something;
return 0;
}

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