Reference or shared_ptr as member for association - c++

I'm writing a class Bar. Bar needs to access an other class Foo to be useful.
So the instance of Foo has to outlive the instance of Bar using it.
I can't decide between two ways to write this. Here is an example:
#include <iostream>
#include <memory>
using namespace std;
struct Foo {
Foo(int _x) : x_(_x) {}
~Foo() {}
int x_;
};
struct Bar1 {
Bar1(Foo& _foo) : foo_(_foo) {}
void print_foo() {cout << foo_.x_ << endl;}
private:
Foo& foo_;
};
struct Bar2 {
Bar2(shared_ptr<Foo> _foo) : foo_{move(_foo)} {}
void print_foo() {cout << foo_->x_ << std::endl;}
private:
shared_ptr<Foo> foo_;
};
int main()
{
Foo f1{1};
shared_ptr<Foo> f2 = make_shared<Foo>(2);
Bar1 b1(f1);
b1.print_foo();
Bar2 b2(f2);
b2.print_foo();
return 0;
}
I think, that Bar1 gives the user more freedom on how to manage the lifetime of Foo
and it probably is more efficient. But it goes in an undefined (not sure if
this is the right word here) state, when the instance of Foo to which foo_ refers is destroyed.
What is the preferred way to handle a situation like this and why?

I think the preferred way to handle this situation depends on the specifics of the situation. As you identified, Bar1 gives the user more freedom with the lifetime of Foo, and is more dangerous. It is also more efficient (slightly), but probably not enough to be a concern.
If you know for a fact (and/or can prove) that Foo will always outlive all of your Bar objects (maybe you allocate the Foo you use on the stack in main), there is no problem using Bar1. If you are unsure, Bar2 would be the way to go. Though the semantics may be wrong with Bar2 (maybe you don't want Bar to keep your Foo alive).
This leads us to a third option: weak_ptr. This would give the user control of the lifetime of Foo, but still allow Bar to have defined behavior when the Foo is destroyed.
struct Bar3 {
Bar3(std::weak_ptr<Foo> _foo) : foo_(_foo) {}
void print_foo_v1() {
// throws if foo_'s object has been destroyed
std::shared_ptr<Foo> foo(foo_);
std::cout << foo->x_ << std::endl;
}
void print_foo_v2() {
// returns nullptr if foo_'s object has been destroyed
std::shared_ptr<Foo> foo(foo_.lock());
if (foo) {
std::cout << foo->x_ << std::endl;
}
}
private:
std::weak_ptr<Foo> foo_;
};

If you know that Foo will outlive Bar use reference-based solution because of simplicity and because it expresses what you want to achieve - that Bar references Foo. If you use pointers then the intent is not that clear.

Related

Optional pointer ownership

Let's consider this class, which owns or views a pointer depending on how it is constructed.
template<class T>
class OptionalUniquePtr
{
public:
OptionalUniquePtr(p*)
: m_p(p)
{}
OptionalUniquePtr(std::unique_ptr<T>&& p)
: m_owned_p(std::move(p))
, m_p(p)
{}
T* get()
{
return m_p;
}
private:
std::unique_ptr<T> m_owned_p;
T *m_p;
};
Apart from tweaks or optimisations, my question is: is this a bad idea?
I'm working on some code that could optionally own or view some pointers:
std::unique_ptr<Bar> b1 = ...;
Bar *b2 = ...;
// one million lines later
Foo f1(std::move(b1),...); // ownership transfered to f1
Foo f2(b2,...); // just viewing b2, caller manages lifetime. Risky, but usually owners have long lifetime
Imagine that Foo is big class which does something on a Bar among other things.
I want Foo to be flexible to accept both, so it could have an OptionalUniquePtr inside. An alternative is templatise Foo like this
Foo<std::unique_ptr<Bar>> f1(std::move(b1),...);
Foo<Bar*> f1(b2,...);
The advantage of this second approach is to be more explicit about memory ownership.
Another alternative is to use std::shared_ptr to start with, but in huge codebases this is not feasible.
What is the community opinion on OptionalUniquePtr?
Thanks
Simone
The answer is that this kind of "optional ownership" is already implemented by std::shared_ptr. The code looks like this:
std::unique_ptr<Bar> bar1 = ...;
Bar* bar2 = ...;
Foo f1(std::move(bar1));
Foo f2(bar2);
where
class Foo
{
public:
// Onwing ctor
Foo(std::unique_ptr<Bar>&& b)
: m_bar_ptr(std::move(b))
{}
// Viewing ctor. It uses shared_ptr aliasing ctor.
Foo(Bar* b)
: m_bar_ptr(nullptr, b)
{}
private:
std::shared_ptr<Bar> m_bar_ptr;
};

Order of static destructors

If a class Foo has a static member variable Bar, I would expect Bar's destructor to run only after the last instance of Foo's destructor runs. This doesn't happen with the code snippet below (gcc 6.3, clang 3.8):
#include <memory>
#include <iostream>
class Foo;
static std::unique_ptr<Foo> foo;
struct Bar {
Bar() {
std::cout << "Bar()" << std::endl;
}
~Bar() {
std::cout << "~Bar()" << std::endl;
}
};
struct Foo {
Foo() {
std::cout << "Foo()" << std::endl;
}
~Foo() {
std::cout << "~Foo()" << std::endl;
}
static Bar bar;
};
Bar Foo::bar;
int main(int argc, char **argv) {
foo = std::make_unique<Foo>();
}
Outputs:
Bar()
Foo()
~Bar()
~Foo()
Why is the order of destruction not the reverse of construction here?
If ~Foo() uses Foo::bar this is a use after delete.
In C++ the objects are constructed in order of occurrence and destructed in the reverse order. First comes foo construction, then bar construction then main is executed then bar is destructed and then foo. This is the behavior you are seeing. The switch appears because the constructor of foo doesn't construct a Foo, it constructs an empty unique_ptr, so you don't get to see Foo() in the output. Then bar is constructed with the output and in main you create the actual Foo after foo has long been constructed.
I would expect Bar's destructor to run only after the last instance of Foo's destructor runs.
No, as a static data member, Foo::bar is independent of any instances of Foo.
And for the code you showed,
static std::unique_ptr<Foo> foo; // no Foo created here
Bar Foo::bar; // Foo::bar is initialized before main(), => "Bar()"
int main(int argc, char **argv) {
foo = std::make_unique<Foo>(); // an instance of Foo is created, => "Foo()"
}
// objects are destroyed in the reverse order how they're declared
// Foo::bar is defined after foo, so it's destroyed at first => "~Bar()"
// foo is destroyed; the instance of Foo managed by it is destroyed too => "~Foo()"
The complication here is that the code doesn’t instrument the constructor of foo. What happens is that foo gets constructed first, than Foo::bar gets constructed. The call to make…unique constructs a Foo object. Then main exits, and the two static objects get destroyed in reverse order of their construction: Foo::bar gets destroyed, then foo. The destructor for foo destroys the Foo object that it points to, which is the one created inmain.
Static objects' lifetimes are based solely on the order of their definition. The compiler doesn't "know enough" when to call Bar::Bar() as much as calling Bar::~Bar().
To illustrate the problem better, consider this
class Foo;
struct Bar {
Bar() {
std::cout << "Bar()" << std::endl;
}
~Bar() {
std::cout << "~Bar()" << std::endl;
}
void baz() {}
};
struct Foo {
Foo() {
bar.baz();
std::cout << "Foo()" << std::endl;
}
~Foo() {
std::cout << "~Foo()" << std::endl;
}
static Bar bar;
};
Foo foo;
Bar Foo::bar;
int main() {}
Prints
Foo()
Bar()
~Bar()
~Foo()
The addition of std::unique_ptr postpones Foo::Foo() after its construction in main, giving the illusion of the compiler "knowing" when to call Bar::Bar().
TLDR Static objects should be defined later than its dependencies. Before defining bar, it is just as much a bug to define a std::unique_ptr<Foo> and to define a Foo
In general, you should not write code which depends on the order of construction or destruction of static (or global) data. This makes unreadable and unmaintainable code (you might prefer static smart pointers, or
explicit initialization or startup routines called from main). And AFAIK that order is not specified when you link several translation units.
Notice that GCC provides the init_priority and constructor (with priority) attributes. I believe you should rather avoid using them. However, the __attribute__(constructor) is useful inside plugins, for plugin initialization.
In some cases, you might also use atexit(3) (at least on POSIX systems). I don't know if such registered functions are called before or after destructors (and I think you should not care about that order).

Is it good practice to use pointers as class members?

I'm fairly new to C++, and I'm trying to understand the good practices for building classes.
Let's say I have a class Foo:
class Foo {
public:
double foo;
Foo(double foo);
Foo add(Foo f);
}
I want to make a class Bar, that is made of two Foo objects, and that creates a third one at construction.
1st option: Objects as class members
class Bar {
public:
Foo foo1;
Foo foo2;
Foo foo3;
Bar(const Foo &f1, const Foo &f2);
}
Bar::Bar(const Foo &f1, const Foo &f2):
{
foo1 = f1;
foo2 = f2;
foo3 = f1.add(f2);
}
As is, it does not work as I have not defined a default constructor for Foo.
2nd option: Pointers as class members
class Bar {
public:
const Foo* foo1;
const Foo* foo2;
const Foo* foo3;
Bar(const Foo &f1, const Foo &f2);
}
Bar::Bar(const Foo &f1, const Foo &f2):
{
foo1 = &f1;
foo2 = &f2;
foo3 = &(f1.add(f2));
}
Note: I have to declare foo1 and foo2 as const for the constructor to work.
It still fails though because for foo3 I am taking the address of a temporary result, which is illegal.
Which option is more natural (and how can I fix the errors)? I feel the first option is probably better, but then my Foo objects have to be created twice in memory, don't they? (once to call the constructor, and a second time by the constructor itself)
Any help appreciated.
It's fine to use pointers as members, but in your case you are simply working around a minor hiccup that really doesn't warrant the use of pointers, and using pointers can be dangerous as evidenced by an issue I'll point out shortly.
As is, it does not work as I have not defined a default constructor for Foo.
This is easily resolved by using initializers for Bar:
Bar(const Foo &f1, const Foo &f2) : foo1(f1), foo2(f2), foo3(f1.add(f2)) {}
as demonstrated here:
#include <iostream>
class Foo {
public:
double m_foo;
Foo(double foo) : m_foo(foo) {}
Foo add(Foo f) { f.m_foo += m_foo; return f; } // returns temporary!
};
class Bar {
public:
Foo m_foo1;
Foo m_foo2;
Foo m_foo3;
Bar(const Foo &foo1, const Foo &foo2);
};
Bar::Bar(const Foo &foo1, const Foo &foo2)
: m_foo1(foo1)
, m_foo2(foo2)
, m_foo3(m_foo1.add(m_foo2))
{
}
int main() {
Foo foo1(20.0);
Foo foo2(22.0);
Bar bar(foo1, foo2);
std::cout << bar.m_foo3.m_foo << "\n";
return 0;
}
Live demo: http://ideone.com/iaNzJv
In your pointer solution you introduce a glaring pointer problem: a pointer to a temporary.
foo3 = &(f1.add(f2));
f1.add returns a temporary Foo, which you take the address of, and then it goes away. This is a dangling pointer.
Your pointer implementation also doesn't explicitly take pointers as its inputs so f1 and f2 could run into the same problem:
Bar(Foo(20), Foo(22)); // two temporary Foos passed by reference
// but having their addresses taken. ouch.
If you're taking pointers, it's best to do that at the api to your class; you're going to have to care about the lifetime of the things pointed to, and try to make it easier for a caller to tell that you are doing so.
Bar(Foo* f1, Foo* f2);
But now if you're going to have F3 you're going to be responsible for managing it's memory:
Bar(Foo* f1, Foo* f2)
: foo1(f1), foo2(f3), foo3(new Foo(*f1.add(*f2)))
{}
~Bar()
{
delete f3;
}
So in your example case, using members is probably drastically better.
Save the use of pointers for large objects that you definitely don't want to copy, and where you can't use a move operation.
--- EDIT ---
The problem of conveying ownership of pointers has been largely solved in modern C++ (C++11 and higher), through "smart pointers", in particular std::unique_ptr and std::shared_ptr.
It is generally considered Best Practice to use these instead of raw pointers, although it requires learning some newer C++ concepts.
#include <memory>
struct Foo {};
class Bar {
public:
std::unique_ptr<Foo> m_f1; // we will own this
std::unique_ptr<Foo> m_f2; // and this
Bar(std::unique_ptr<Foo> f1) // caller must pass ownership
: m_f1(std::move(f1)) // assume ownership
, m_f2(std::make_unique<Foo>()) // create a new object
{}
~Bar()
{
// nothing to do here
}
};
int main() {
auto f = std::make_unique<Foo>();
Bar(std::move(f)); // the 'move' emphasizes that
// we're giving you ownership
// 'f' is now invalid.
return 0;
}
Live demo: http://ideone.com/9BtGkn
The elegance of this is that when Bar goes out of scope, the unique_ptrs will ensure that the objects they own are destroyed for us -- we don't have to remember to delete them.
In the above example, it would probably have been much better to make m_f2 a member rather than a pointer.
If the objects are not too expensive to pass around, I suggest using objects as members.
If you need to use pointers for some reason, you need to have ownership policies in place. Does Bar object own the objects? Does Bar just holds the pointers to the objects but is not responsible for releasing resources used by them?
If Bar owns the Foo objects, prefer to use one of the smart pointers. You'll need to make copies of those objects by using new and hold on to those pointers.
Here's how I see it:
class Bar {
public:
std::unique_ptr<Foo> foo1;
std::unique_ptr<Foo> foo2;
std::unique_ptr<Foo> foo3;
Bar(const Foo &f1, const Foo &f2) : foo1(new Foo(f1)), ... {}
};
std::unique_ptr does not have a copy constructor. Hence, you must provide a copy constructor for Bar and initialize its members from the copy appropriately.
If Bar does not own the Foo objects, you might be able to get by using references as member data.
class Bar {
public:
Foo const& foo1;
Foo const& foo2;
Foo const& foo3;
Bar(const Foo &f1, const Foo &f2) : foo1(f1), ... {}
};
I think it is nonsense that the object is the same as a primitive variable.
class Foo {
public:
double _stocks;
Business* _business;
Foo(double stocks, Business* business):_stocks(stocks), _business(business){}
Foo* add(const Foo& f) {
_stocks += f._stocks;
_busines->merge(f._business);
return this;
}
virtual ~Foo() { delete _business; }
}
class Bar {
public:
Foo* _foo1;
Foo* _foosub;
// Foo* _foo3;
Bar(Foo* f1, Foo* f2); // unable const for f1 at least
}
Bar::Bar(Foo* f1, Foo* f2):
{
_foo1 = f1;
_foosub = f2;
_foo1.add(*f2);
// _foo3 is the same as _foo1
}
void main() {
Foo company1(100.00, BusinessFactory.create("car"));
Foo company2(2000.00, BusinessFactory.create("food"));
Bar conglomerate(&company1, &company2);
// to be continued
}

What method do you use to initialize member variables?

Suppose I have a class Foo, with a member variable that is a std::vector of floats, bar. I then create an instance of Foo, called foo. Let's say that I do not know the length of bar before the program runs, but at the point when foo's constructor is called, I know that it's length should be x.
There are three ways I can think of to initialize the length of bar, and I'm just wondering which of the three most people tend to use. I have ranked them in order of what I would consider to be "best practice", but I'm more curious about what method people "actually" use in practice. Sometimes I use methods which make the code clearer to follow, rather than necessarily following best practice...
bar is a private member, and I resize it during foo's constructor, e.g. Foo foo(x){bar.resize(x)};
bar is a private member, and I call foo.ResizeBar(x) which resizes bar internally, after creating foo.
bar is a public member, and I call foo.bar.resize(x), after creating foo.
Or, in code:
1.
class Foo
{
private:
std::vector<float> bar;
public:
Foo(int x)
{
bar.resize(x);
};
};
int main()
{
Foo foo(100);
return 0;
}
2.
class Foo
{
private:
std::vector<float> bar;
public:
Foo()
{
};
void ResizeBar(int x)
{
bar.resize(x);
};
};
int main()
{
Foo foo;
foo.ResizeBar(100);
return 0;
}
3.
class Foo
{
public:
std::vector<float> bar;
Foo()
{
};
};
int main()
{
Foo foo;
foo.bar.resize(100);
return 0;
}
The problem with all three of your methods is that you're needlessly invoking the default initializer for your vector, and then modifying the already initialized vector to suit your needs.
You should be invoking the correct initializer using the initializer list:
Foo::Foo(std::size_t x) : bar(x, 0) { }
The best method is not in the list of options you posted. The best method is to initialize bar using member initializer lists.
Foo::Foo(int x) : bar(x) {}

Virtual function calling a non-virtual function

I wrote the following piece of code to test my understanding of virtual inheritance. Apparently, I still don't get it fully. Here is my code (followed by my question):
#include <iostream>
#include <vector>
using namespace std;
class Foo
{
public:
virtual void foo();
void foo2();
};
void Foo::foo()
{
cout << "In FOO - foo 1" << endl;
foo2();
}
void Foo::foo2()
{
cout << "In FOO - foo 2" << endl;
}
class Bar : public Foo
{
public:
void foo();
void foo2();
};
void Bar::foo()
{
cout << "In BAR - foo 1" << endl;
foo2();
}
void Bar::foo2()
{
cout << "In BAR - foo 2" << endl;
}
int main()
{
Foo* f = new Foo;
f->foo();
Foo* b = new Bar;
b->foo();
return 0;
}
This is my understanding:
The pointer f points to the base class Foo and f->foo() calls foo() in the base class which in turn calls foo2() in the base class.
The pointer b is a base-class pointer but points to an object of the derived class Bar. Now, since foo() is a virtual function, it calls foo() of the derived class. Now foo() (of the derived class) calls foo2(). Since foo2() is not a virtual function, I was expecting the base class foo2() to get called. However I see that foo2() of the derived class is getting called.
So, I was expecting this output:
In FOO - foo 1
In FOO - foo 2
In BAR - foo 1
In FOO - foo 2
but got this instead:
In FOO - foo 1
In FOO - foo 2
In BAR - foo 1
In BAR - foo 2
Why is this so? From what I understand, the vtable will have an entry only for foo() and not for foo2(). So, how is foo2() of the derived class getting called?
This is my first post. Please excuse me if I have broken any posting guidelines. Thanks in advance!
In Bar::foo(), you are calling foo2(). This is really equivalent to calling this->foo2(). The type of this is Bar, so this is really equivalent to:
void Bar::foo()
{
Bar *bar = this;
bar->foo2();
}
So there's no polymorphism involved at this point; the call is resolved to Bar::foo2 at compile-time, rather than dynamically at run-time.
because Bars foo is what's calling foo2, at that stage it knows its a Bar....
try again, except call foo2 directly in main for both rather than foo calling foo2
int main()
{
Foo* f = new Foo;
f->foo();
f->foo2();
Foo* b = new Bar;
b->foo();
b->foo2();
return 0;
}
how is foo2() of the derived class getting called?
You expect Bar::foo2 to never be called. Then your question can be reformulated as: "why is the purpose of Bar::foo2, if any?"
Its purpose is to be called when dealing with Bar objects. The foo2 of a Bar object is called whenever foo2 is called.
It is only for foo objects that it matters whether Foo::bar2 is virtual or not. Inheritance never forces you to use the functions with the same signature in the base class, if you are dealing directly with derived class objects. (It would cause too many unpleasant surprises to have the inheritance rules work differently in this matter.)
What you have essentially done is hiding. By creating a function with the same signature in Bar, you have hidden the nonvirtual function in the base class Foo. This is typically a bad design because it is unnecessarily complex - it is better to choose different names for different things, to avoid hiding. Hiding is seldom part of a conscious good design.
void Bar::foo()
{
cout << "In BAR - foo 1" << endl;
foo2();
}
This is because Bar::foo2() is the foo2() called by foo(). Bar::foo2() is local to Bar::foo() and has precedence. It's just static dispatch from Bar::foo2().
If the behavior you expected is what you really want, you can choose the method by specifying its scope like so:
void Bar::foo()
{
cout << "In BAR - foo 1" << endl;
Foo::foo2();
}
So this really does not have to do with dynamic dispatch.