-1

I want to create an instance of a class using new, but I want to convert to reference for further usage other than using pointer. Currently I am using this line Foo& rf = *f; to convert explicitly, it seems a bit silly. Any better and more elegant ways to create a reference variable and referring a new created instance?

Here are some code to show what I am doing,

class Foo{
    public:
    Foo(){

    }

    void printValue() {
        cout << "This is Foo object " << endl;
    }
};

int main() {
    Foo* f = new Foo();
    Foo& rf = *f;
    rf.printValue();
    f -> printValue();
}
Lin Ma
  • 9,739
  • 32
  • 105
  • 175
  • 3
    I am no expert, but i believe there is no better way to create a reference to the newly created object than dereferencing the pointer. I am wondering what would be the use, or why you want another method tho. – puelo Sep 23 '17 at 21:55
  • 1
    Your program leaks. And it's more likely to retain a leak if you keep using a reference. Eyebrows will be raised at `delete &rf;` – StoryTeller - Unslander Monica Sep 23 '17 at 21:56
  • 4
    " but I want to convert to reference for further usage other than using pointer." - why? –  Sep 23 '17 at 21:56
  • @NeilButterworth, I need to call another function which only accept reference, it is not written by me, I have to pass reference, any thoughts? – Lin Ma Sep 23 '17 at 21:57
  • 1
    You should also consider using shared_ptr/unique_ptr. – Yuval Ben-Arie Sep 23 '17 at 21:57
  • 2
    @LinMa What is wrong with `functionToCall(*f)`? – puelo Sep 23 '17 at 21:58
  • @StoryTeller, I think it is the same to manage memory using reference and pointer, what diff do you mention? – Lin Ma Sep 23 '17 at 21:58
  • 7
    Better still, `Foo f; func(f);` solves pretty much *everything*, including your reference misunderstanding, your memory leak, etc. – WhozCraig Sep 23 '17 at 21:59
  • @puelo, it looks a bit ugly using `*`. But I am not expert, if it is ok, I can use it. :) – Lin Ma Sep 23 '17 at 21:59
  • 1
    Well, `func( * f);` - but are you sure youreally need to create the object dynamically? –  Sep 23 '17 at 21:59
  • 2
    Consider reading a [book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). You seem to have some incorrect assumptions about memory management, references and arguments. – nwp Sep 23 '17 at 22:00
  • @NeilButterworth, yes, I can definitely call using the way you mentioned, but an additional `*` looks ugly. It is normally ok to add an additional `*`? I am not expert. – Lin Ma Sep 23 '17 at 22:00
  • 2
    @LinMa well that is c++ pointer syntax. Nothing to be done here. But as others suggested maybe evaluate if you really need an object on the heap . – puelo Sep 23 '17 at 22:00
  • 5
    Get over your hangups about "looks a bit silly", "looks ugly", etc. It's how the language works. Stop trying to make it into something it isn't. – WhozCraig Sep 23 '17 at 22:01
  • 1
    @WhozCraig, thanks. I am from Python. Sometimes diff feeling. Trying to adapt. :) – Lin Ma Sep 23 '17 at 22:02
  • @puelo, it makes sense. If you could add a reply, I will mark it as answer to help other people. – Lin Ma Sep 23 '17 at 22:02
  • @LinMa - The difference is that you don't normally do dynamic allocation to release the memory at the same scope. It may be released at a completely different place. And functions that accept a reference should not be deleting the referenced item. Too easy to call them with an automatic variable. – StoryTeller - Unslander Monica Sep 23 '17 at 22:03
  • I think you can flag delete the question. I don't see the value to be honest. But you are welcome to answer it yourself after some research ;) – puelo Sep 23 '17 at 22:04
  • If you don't want a pointer, just don't use `new`. – Bo Persson Sep 23 '17 at 22:44
  • Your question's header does not reflect actual question, I guess that's why you got so many down votes. – Liastre Sep 25 '17 at 14:10
  • A C++ pointer parameter might be nullptr. It is simply useful, and may be intentional. But the idea is something that a reference does not imply. Also, when the lifetime (of the new'd object) starts and ends in main, I no longer need 'global' objects, and simply pass the reference, but yes, if there is auto var space to spare, I probably would not new the small item. – 2785528 Sep 26 '17 at 22:44

4 Answers4

2

You can write this:

Foo* foo = new Foo();
Foo& fooRef = *foo;

in one line:

Foo& fooRef = *new Foo();

But, be aware, you should delete your allocated memory later anyway:

delete &fooRef;

I do not suggest you write code in this way, to avoid memory leaks. Look into this answer for further details. Choose smart pointers or containers when it possible.

Liastre
  • 1,281
  • 11
  • 29
  • In most environments, the code is required to confirm that 'new' succeeded. i.e. assert (new Foo()); – 2785528 Sep 25 '17 at 02:57
  • @DOUGLASO.MOEN no need for additional checks, in modern C++ operator `new` [throws an exception std::bad_alloc](http://www.cplusplus.com/reference/new/operator%20new/) on failure, unless you're explicitly using the nothrow version. – Liastre Sep 25 '17 at 07:12
  • I had not noticed that, it appears to be a C++11 (and later) feature? About a decade ago, the C++ embedded telecom teams I had worked with were too conservative to tolerate C++ exceptions (see FUD factor). Now, what do you suppose will happen with the reused code in current efforts? – 2785528 Sep 26 '17 at 22:36
  • @DOUGLASO.MOEN operator `new` throws exception since C++98, C++11 provided new keyword `noexcept` so syntax has changed a bit. I know sometimes developers avoid using of exceptions for different reasons, but it's really appropriate and right way to handle any kind of errors, it makes your code more meaningful, local, maintainable and scalable. – Liastre Sep 27 '17 at 07:50
1

... convert to reference for further usage other than using pointer.

I prefer references (and avoid pointers) deep in my code. Mostly because a nullptr can have special meaning (that a reference will not) that needs some thought to confirm, the next time I review the code.

My solution is to new the bigger-than-automatic-memory object to get a pointer at the appropriate level for lifetime. I then invoke the using methods or functions with the dereferenced pointer. This keeps the pointer (at the lifetime start, such as main) as is, and later still available for the delete.

// bigData  used many places
void use1_of_Data (BigData_t& bigData, Small_t& sd) {
    //... do something with data
}

void use2_of_Data (BigData_t& bigData, Small_t& sd) {
    //... do something with data
}

//...
void use3_of_Data (BigData_t& bigData, Small_t& sd) {
    //... do something with data
}

int main(int argc, char* argv[]) 
{
   // ...
   BigData_t* bd = new BigDta_t; // (sizeof(BigData_t) > autovar space)
   Small_t    sd;
   {
      assert(nullptr != bd); 
      // note - bd lasts the lifetime of program

      use1_of_Data (*bd, sd);
      use2_of_Data (*bd, sd);
      //...
      use3_of_Data (*bd, sd);
   }
   // what's new'd in main, is deleted in main
   delete bd;        
}
2785528
  • 5,438
  • 2
  • 18
  • 20
  • Did you know that `assert()` may be removed by compiler at release build, since it's supposed to be used only for debug? – Liastre Sep 27 '17 at 07:57
  • No, and thanks for the info. I know practically nothing about the 'release build', but I will guess you are referring to a part of Visual Studio. On Linux and vxWorks, the assert() code is not 'null-ified' unless you set NDEBUG. There is no (apparent) connection to build type. I have worked on teams which have shipped code with asserts enabled, but I also have some small evidence that doing so is a some what uncommon practice. – 2785528 Sep 29 '17 at 16:47
0

As others have said, if the Foo instance's non-heap contents aren't so large that the Foo instance itself needs to be allocated on the heap, it is better to just use the stack:

Foo foo;
foo.printValue();

However, if it does need to be allocated on the heap for some reason, then it's dangerous to hold the only reference to it in an ordinary pointer, since if an exception gets thrown by any code, it will never be deallocated. In fact, most modern C++ guidelines advise not using ordinary pointers to own data for this reason:

Foo * fooPtr = new Foo();
doSomething();  // If an exception is thrown here, the Foo never gets deallocated!
Foo& foo = *fooPtr;
foo.printValue(); // If printValue throws an exception, the Foo never gets deallocated!
delete foo;

If you aren't familiar with this sort of problem, I suggest googling RAII ("Resource Acquisition Is Initialization") which is an crucial concept to understand when programming in C++.

An easy way to implement RAII in a case like this is through use of a smart pointer (std::shared_ptr or std::unique_ptr).

An extra reference variable can still be helpful to avoid having to use the arrow operator to call functions on the smartpointer. I disagree with some other answerers who don't see value in also binding a local reference to a value already held in a local pointer. I prefer to use references whenever possible, since when I use a reference, I can be sure that the reference isn't null (references should always refer to actual objects), while when I use a pointer (even a smart pointer) I must always be careful that my code correctly handles the case where the pointer is null. When the pointer initialization occurs close to the pointer's use, this may not be a big deal, but when they are separated, it can become hard to trace through the code to be sure the pointer can't be null. A reference makes this self-documenting.

I think that it is often useful to first ensure that a pointer or smart pointer value can't be null, and then to bind a local reference to the pointed-to value, since I can then use the reference freely without having to worry at each use about the possibility of it being null:

std::unique_ptr<Foo> fooPtr = std::make_unique<Foo>(/* Foo constructor args go here */);
doSomething(); // Now if an exception thrown here, Foo gets deallocated.
Foo& foo = *fooPtr; // We know the pointer is not null here (it just
                    // got returned from make_unique which
                    // didn't throw a bad_alloc exception) so it's
                    // safe to bind a reference to it here.
                    // Also, this reference has lifetime less than the
                    // smart pointer, so will never outlive it.

// .. many lines of code later ..
foo.printValue(); // No need to worry about null here.
                  // If exception thrown here, the unwinding of the stack
                  // causes fooPtr to deallocate Foo.

// No need to call delete here.
// fooPtr will automatically deallocate Foo when it goes out of scope.
Some Guy
  • 405
  • 8
  • 15
-1

If we speak about elegance, may I suggest you to use a shared_ptr?

#include <iostream>
#include <memory>

using namespace std;

class Foo{
    public:
    Foo(){

    }

    void printValue() {
        cout << "This is Foo object " << endl;
    }
};

int main(int argc, char *argv[])
{
    Foo* f = new Foo();
    std::shared_ptr<Foo> mySharedPtr(f);
    f->printValue();
    mySharedPtr.get()->printValue();

    return 0;
}
Danilo Carrabino
  • 397
  • 6
  • 12
  • 1
    `mySharedPtr.get()->printValue();` could as well be used as `mySharedPtr->printValue();`. No need to use `get()` since `std::shared_ptr` has defined `operator ->` – Fureeish Sep 23 '17 at 22:31