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
}
Related
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;
};
Given the following class:
class Foo
{
public:
//...
private:
Bar mBar;
};
Is it possible to expose the mBar member in such a way that it's members can be accessed, but not the mBar object itself?
The reason is that users should be able to access all of mBar's members but they should not be able to assign another Bar instance to mBar.
Bar has a lot of members and it would be cumbersome to write getters/setters and forwarding fuctions for them all. But if mBar is made public one is able to do aFoo.mBar = Bar(/*...*/);which is the only thing that should not be allowed.
Deleting Bar's assignment operators is not an option.
if you only want to protect against errors and not Machiavelli, operator-> might help (you might probably want a wrapper instead of directly put it in foo though):
class Foo
{
public:
//...
const Bar* operator ->() const { return &mBar; }
Bar* operator ->() { return &mBar; }
private:
Bar mBar;
};
so
Foo foo;
foo->bar_member;
foo.foo_member;
// Machiavelli
*foo.operator->() = Bar();
I would probably rethink your design but here is a possible indirect way using an intermediate get method:
struct Bar {
int intAttr;
};
class Foo {
Bar mBar;
public:
template <class U>
U& get(U Bar::* p) {
return mBar.*p;
}
};
This way, you can access any public member of mBar using:
Foo foo;
foo.get(&Bar::intAttr); // get
foo.get(&Bar::intAttr) = 0; // set
I have a struct of Foo:
struct Foo
{
};
I have a struct of Bar:
struct Bar
{
};
They are handled by 2 more structs which maintain (add/remove) a pointer array of each:
struct FooContainer
{
Foo** FooList;
// add(), remove() etc
};
struct BarContainer
{
Bar** BarList;
// add(), remove() etc
};
Now, what I WANT is another struct called Baz which links (in a one-to-many fashion) Foo to Baz. I can't (for reasons not explained here) refer to them by index, it must be by pointer/reference.
Something like this:
struct Baz
{
Foo* foo;
Bar* bar;
};
If I wanted to add a constructor to Baz which took these non-const pointers, how would I do it?
Baz should allow me to change which instance of Foo and Bar it points to... so it's pointers don't want to be const.
Do I pass the pointers into the constructor as const and then do something with them as I would if I were passing a reference to a struct? I then get issues with trying to set the value of a non-const pointer to a const pointer.
I hope this question makes sense...
Edit: Should I use reference instead of pointer?
Baz should allow me to change which instance of Foo and Bar it points to... so it's pointers don't want to be const.
That is correct, you don't want to store constant pointers. However, it does not prevent you to store pointers to const, which is not the same thing.
This sounds confusing, so here is an illustration using your Baz example:
struct Baz
{
const Foo* foo;
const Bar* bar;
Baz(const Foo* newFoo, const Bar* newBar) : foo(newFoo), bar(newBar) {}
void setFoo(const Foo* newFoo) { foo = newFoo; }
void setBar(const Bar* newBar) { bar = newBar; }
};
everything is going to compile fine: it's Foo and Bar pointed to by foo and bar that are const, not the pointers themselves, which leaves you free to change the pointers as you wish.
This, on the other hand, is not going to compile:
struct Baz
{ // Note how const has moved to the other side of the asterisk
Foo* const foo;
Bar* const bar;
Baz(Foo* newFoo, Bar* newBar) : foo(newFoo), bar(newBar) {}
void setFoo(Foo* newFoo) { foo = newFoo; } // BROKEN!!!
void setBar(Bar* newBar) { bar = newBar; } // BROKEN!!!
};
Now the pointer, not the "pointee", is const, preventing you from changing foo or bar members.
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.
How can I find out when a temp object is being created and destructed and how?
For an example lets say we have a class named Foo
and a function that return a Foo object, and its parameters are an object, and a reference to an object.
Foo func(Foo a ,Foo & b);
How many objects are created with me knowing it?
Is it created using copy constructor or regular?
Using the constructor and destructor, insert a print statement into them.
#include <iostream>
class Foo
{
public:
Foo(){}
Foo(const Foo &other) {std::cout<<"A copy was made\n";}
Foo(Foo &&other) {std::cout<<"Foo was moved\n";}
~Foo(){std::cout<<"Destroyed Foo\n";}
};
Foo func(Foo a, Foo &b)
{
return a;
}
Foo func_const(const Foo &a, Foo &b)
{
return a;
}
Foo func_temp()
{
return Foo();
}
int main()
{
Foo f;
func(f, f);
std::cout<<"\n\n\n";
func_const(f, f);
std::cout<<"\n\n\n";
Foo g = func_temp();
}
The above prints (using ideone):
Foo constructed
A copy was made
Foo was moved
Destroyed Foo
Destroyed Foo
A copy was made
Destroyed Foo
Destroyed Foo
Destroyed Foo
With the function signature:
Foo func(Foo a, Foo &b), parameter a may make a copy. The copy may also be elided by the compiler's optimisation. Parameter b never makes a copy as it is pass by reference and that usually says that you will be modifying the object passed; not modifying a copy.
When returning a Foo, it may or may not return a copy. It depends on the definition of your class. See http://en.wikipedia.org/wiki/Return_value_optimization