References in C++ are a conveneint construct that allow us to simplify the following C code:
f(object *p){
//do something
}
int main(){
object* p = (object*) calloc(sizeof(object));
f(p);
}
to
f(object& o){
//do something
}
int main(){
object o = object();
f(o);
}
Shared pointers are another convenience in C++ that simplify memory management. However, I am not sure how to pass a shared_ptr to a function like f(object& o) which accepts arguments by reference?
f(object& o){
//do something
}
int main(){
shared_ptr<object> p (new object());
f(*p);
}
Will the shared pointer be incremented when its object is passed by reference to a function?
Take a shared_ptr by value, and the reference count will increase. This is easier when you typedef it:
typedef boost:shared_ptr<object> object_ptr;
void foo(object_ptr obj)
{
obj->/* stuff*/;
obj.reset(); //only resets this local copy, that means:
// reduce reference count (back to 1), and
// set obj to point at null.
}
int main(void)
{
object_ptr obj(new object());
foo(obj);
}
Keep in mind references are aliases. When you pass by reference, you're not passing pointers, copies, etc..., you're aliasing another object. (In reality they are implemented as pointers):
typedef boost:shared_ptr<object> object_ptr;
void foo(object_ptr& obj)
{
obj.reset(); // the references was never increased, since a copy has not
// been made, this *is* obj in main. so the reference
// goes to 0, and obj is deleted
}
int main(void)
{
object_ptr obj(new object);
foo(obj); // after this, obj has been reset!
}
Always remember to be const correct, to prevent errors:
typedef boost:shared_ptr<object> object_ptr;
void foo(const object_ptr& obj)
{
obj.reset(); // cannot do!
}
int main(void)
{
object_ptr obj(new object);
foo(obj);
}
I think you should prefer to pass smart pointers as references when possible, to avoid extraneous increments and decrements (and copies and whatnot).
Will the shared pointer be incremented when its object is passed by reference to a function?
No, as you are accessing the raw pointer and then passing it. You want to do something similar to this:
f(shared_ptr<object> o){
//do something
}
int main(){
shared_ptr<object> p (new object());
f(p);
}
f(object& o){
//do something
}
int main(){
shared_ptr<object> p (new object());
f(*p);
}
Will the shared pointer be incremented
when its object is passed by reference
to a function?
In the code above - no. p will have its reference counter equal to 1 at all times. You can verify this in a debugger. shared_ptr's reference counter counts the number of shared_ptr instances that point to the same object, it doesn't track references you create by calling operator* (). And it doesn't have to - since p is guaranteed to live until the end of the scope and the function call is in this same scope (or deeper) p will be there during the entire call to f(). So everything is OK.
... unless in f you take the address of o and store somewhere that will last after f returns. This you should avoid by all means - pass the shared_ptr if you need to do that.
First things first, from a functionality point of view, references in C++ are exactly the same as pointers. They only reason they were added to the language was to make the syntax of operator overloading be more natural. (For example to allow one to write a+b instead of &a+&b)
Your C and C++ code samples are absolutely not equivalent. The C version of your C++ code would be:
f(object *p){
//do something
}
int main(){
object o;
object_constructor(&o);
f(&o);
object_destructor(&o);
}
In fact, this is the kind of code that your C++ compiler will conceptually generate.
With regards to your second question: Yes, that is the correct way to call the function f. The shared pointer counter will not be incremented. The actual pointer to the object will be passed, as if you were not using a shared_ptr. It is safe however, as long as f isn't doing anything funky. Just remember that the same thing exactly is happening as if f's parameter took a pointer instead of a reference. The only difference is that the compiler automagically passes the address of the variable without you having to explicitly use the & operator.
I personally do not like to ever pass variables by reference(passing by const reference is ok though). I prefer to use a pointer instead since it makes it clearer at the call site that the function that we are calling may potentially modify it's argument(since the & symbol is visible at the call site).
Peace
Related
Suppose I have a method that defines a shared_ptr. After the method finishes, the shared_ptr will also be deleted. In the interim I have another member that uses that shared_ptr. So I would like to extend the lifetime of the shared_ptr past the initial method.
void initial_method(int input)
{
std::shared_ptr<int> a { std::make_shared<int>(input) };
some_delayed_method(a);
}
Is it possible to manually increase the reference count of a by one in this example?
some_delayed_method() is like a detachment and is referring to a at a time after the initial_method() has returned.
Since you can't call some_delayed_method without a shared_ptr to the object and any shared_ptr to the object extends its lifetime, there is nothing you need to do.
If some_delayed_method saves the pointer in some external data structure, and this pointer will later be used, you should use shared_ptr for that.
class X
{
public:
void initial_method(int input)
{
std::shared_ptr<int> a { std::make_shared<int>(input) };
some_delayed_method(a);
}
void some_delayed_method(const std::shared_ptr<int>& a)
{
use_later = a;
}
private:
std::shared_ptr<int> use_later;
}
This way, the reference count will be handled automatically.
You may insist on using a raw pointer to save the data for later:
void some_delayed_method(const std::shared_ptr<int>& a)
{
use_later = a.get();
}
...
int* use_later;
This is not a proper way to save the data. To make it work (or appear to work), you have to do some hack. For example, make another reference to the data, and leak it:
void some_delayed_method(const std::shared_ptr<int>& a)
{
use_later = a.get();
new std::shared_ptr<int>(a); // horrible hack; please never do it! but it works...
}
This hack leaks the allocated std::shared_ptr so it can never be deleted, thus its refcount is not decremented and the allocated int is leaked.
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();
}
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.
... 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;
}
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.
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;
}
I have in my project a couple of functions that create objects. For example, if you have a function that makes an object like this:
int& f()
{
int *i = new int(5);
return *i;
}
and then when you call that you do
int x = f();
or something like
std::cout << f();
what happens to the int that was created in the function? Is the reference handled like a normal variable or am I doing something terribly wrong? And if so, what is the correct way to make objects?
This is terribly wrong, indeed. The moment you forget about your reference is the moment you'll leak a resource. And you're doing just that with int x = f();.
Same with the second case, std::cout << f(); - don't use this at all if you aren't going to delete that dynamically allocated int.
int is also passed to std::basic_ostream::operator<< by value, a copy is made. This doesn't actually matter, no normal code would accept a reference and then call delete &ref;.
Here's a link for you: RAII.
I can't know what you want from your contrived example, but consider returning by value, or using smart pointers in case of polymorphism.
if you want to show that function delegates ownership of the created object with new you have to do it explicitly for example with std::unique_ptr. As you can see your function becomes self documented and you need not look into the body to understand who response for deleting:
std::unique_ptr<int> foo() {
return std::make_unique<int>(5);
}
C++ references are still confusing to me. Suppose I have a function/method which creates an object of type Foo and returns it by reference. (I assume that if I want to return the object, it cannot be a local variable allocated on the stack, so I must allocate it on the heap with new):
Foo& makeFoo() {
...
Foo* f = new Foo;
...
return *f;
}
When I want to store the object created in a local variable of another function, should the type be Foo
void useFoo() {
Foo f = makeFoo();
f.doSomething();
}
or Foo&?
void useFoo() {
Foo& f = makeFoo();
f.doSomething();
}
Since both is correct syntax: Is there a significant difference between the two variants?
Yes, the first one will make a copy of the returned reference, while the second will be a reference to the return of makeFoo.
Note that using the first version will result in a memory leak (most likely), unless you do some dark magic inside the copy constructor.
Well, the second will result in a leak as well unless you call delete &f;.
Bottom line: don't. Just follow the crowd and return by value. Or a smart pointer.
Your first code does a lot of work:
void useFoo() {
Foo f = makeFoo(); // line 2
f.doSomething();
}
Thinking of line 2, some interesting things happen. First, the compiler will emit code to construct a Foo object at f using the default constructor of the class. Then, it will call makeFoo(), which also creates a new Foo object and returns a reference to that object. The compiler will also have to emit code that copies the temporary return value of makeFoo() into the object at f, and then it will destroy the temporary object. Once line 2 is done, f.doSomething() is called. But just before useFoo() returns, we destroy the object at f, as well, since it is going out of scope.
Your second code example is much more efficient, but it's actually probably wrong:
void useFoo() {
Foo& f = makeFoo(); // line 2
f.doSomething();
}
Thinking of line 2 in that example, we realize that we don't create an object for f since it is just a reference. The makeFoo() function returns an object that it has newly allocated, and we keep a reference to it. We call doSomething() through that reference. But when the useFoo() function returns, we don't ever destroy the new object that makeFoo() created for us and it leaks.
There's a few different ways to fix this. You could just use the reference mechanism you have in your first code fragment, if you don't mind the extra constructors, creation, copying and destruction. (If you have trivial constructors and destructors, and not much (or none) state to copy, then it doesn't matter much.) You could just return a pointer, which has the strong implication that the caller is responsible for managing the life cycle of the referenced object.
If you return a pointer, you've implied that the caller must manage the life cycle of the object, but you haven't enforced it. Someone, someday, somewhere will get it wrong. So you might consider making a wrapper class that manages the reference and provides accessors to encapsulate the management of the objects. (You could even bake that into the Foo class itself, if you wanted to.) A wrapper class of this type is called a "smart pointer" in its generic form. If you're using the STL, you'll find a smart pointer implementation in the std::unique_ptr template class.
A function should never return a reference to a new object that gets created. When you are making a new value, you should return a value or a pointer. Returning a value is almost always preferred, since almost any compiler will use RVO/NRVO to get rid of the extra copy.
Returning a value:
Foo makeFoo(){
Foo f;
// do something
return f;
}
// Using it
Foo f = makeFoo();
Returning a pointer:
Foo* makeFoo(){
std::unique_ptr<Foo> p(new Foo()); // use a smart pointer for exception-safety
// do something
return p.release();
}
// Using it
Foo* foo1 = makeFoo(); // Can do this
std::unique_ptr<Foo> foo2(makeFoo()); // This is better
I have some confusion about the shared_ptr copy constructor. Please consider the following 2 lines:
It is a "constant" reference to a shared_ptr object, that is passed to the copy constructor so that another shared_ptr object is initialized.
The copy constructor is supposed to also increment a member data - "reference counter" - which is also shared among all shared_ptr objects, due to the fact that it is a reference/pointer to some integer telling each shared_ptr object how many of them are still alive.
But, if the copy constructor attempts to increment the reference counting member data, does it not "hit" the const-ness of the shared_ptr passed by reference? Or, does the copy constructor internally use the const_cast operator to temporarily remove the const-ness of the argument?
The phenomenon you're experiencing is not special to the shared pointer. Here's a typical primeval example:
struct Foo
{
int * p;
Foo() : p(new int(1)) { }
};
void f(Foo const & x) // <-- const...?!?
{
*x.p = 12; // ...but this is fine!
}
It is true that x.p has type int * const inside f, but it is not an int const * const! In other words, you cannot change x.p, but you can change *x.p.
This is essentially what's going on in the shared pointer copy constructor (where *p takes the role of the reference counter).
Although the other answers are correct, it may not be immediately apparent how they apply. What we have is something like this:
template <class T>
struct shared_ptr_internal {
T *data;
size_t refs;
};
template <class T>
class shared_ptr {
shared_ptr_internal<T> *ptr;
public:
shared_ptr(shared_ptr const &p) {
ptr = p->ptr;
++(ptr->refs);
}
// ...
};
The important point here is that the shared_ptr just contains a pointer to the structure that contains the reference count. The fact that the shared_ptr itself is const doesn't affect the object it points at (what I've called shared_ptr_internal). As such, even when/if the shared_ptr itself is const, manipulating the reference count isn't a problem (and doesn't require a const_cast or mutable either).
I should probably add that in reality, you'd probably structure the code a bit differently than this -- in particular, you'd normally put more (all?) of the code to manipulate the reference count into the shared_ptr_internal (or whatever you decide to call it) itself, instead of messing with those in the parent shared_ptr class.
You'll also typically support weak_ptrs. To do this, you have a second reference count for the number of weak_ptrs that point to the same shared_ptr_internal object. You destroy the final pointee object when the shared_ptr reference count goes to 0, but only destroy the shared_ptr_internal object when both the shared_ptr and weak_ptr reference counts go to 0.
It uses an internal pointer which doesn't inherit the contests of the argument, like:
(*const_ref.member)++;
Is valid.
the pointer is constant, but not the value pointed to.
Wow, what an eye opener this has all been! Thanks to everyone that I have been able to pin down the source of confusion to the fact that I always assumed the following ("a" contains the address of "b") were all equivalent.
int const *a = &b; // option1
const int *a = &b; // option2
int * const a = &b; // option3
But I was wrong! Only the first two options are equivalent. The third is totally different.
With option1 or option2, "a" can point to anything it wants but cannot change the contents of what it points to.
With option3, once decided what "a" points to, it cannot point to anything else. But it is free to change the contents of what it is pointing to. So, it makes sense that shared_ptr uses option3.