Let's say I have a class FooContainer that aggregates unique_ptr objects of type Foo
#include <vector>
#include <memory>
class FooContainer
{
protected:
std::vector<std::unique_ptr<Foo>> many;
//other attributes
public:
FooCoontainer(const FooContainer&);
//handling functions for Foo
};
The question is how to correctly implement deep copy constructor, and what is syntax for it. Simply assigning
FooContainer::FooContainer(const FooContainer& fc)
{
many=fc.many;
}
will attempt to copy the pointers and will be (thankfully) disallowed by the compiler for unique_ptr. so I would need to do something like this
FooContainer::FooContainer(const FooContainer& fc)
{
many.reserve(fc.many.size());
for(int i=0;i<fc.many.size();i++)
many.emplace_back(new Foo(*fc.many[i]));//assume that Foo has a copy constructor
}
Is this the way to do it? Or may be I should use shared_ptr instead of unique_ptr?
I also have an additional question.
The reason to go for smart pointers (and also for protected in the code above) is that I have derived class BarContainer that aggregates objects Bar in many, which are in turn subclass of Foo. Since the the handling of Bar is very similar to Foo this approach will allow to save a lot of duplicate code compared to two separate classes.
However,. the copy constructor of the BarContainer is problematic. It will the call copy constructor of FooContainer, that will go agead and copy only the Foo part instead of whole Bar. even worse, any invocation of the virtual methods of Bar will call the version of Foo.
So I need a way to override this behaviour.Making the copy constructor virtual is not possible.
Also the copy constructor of Bar could discard the result of Foo copy constructor and to dperform correct copying, but this is quite inefficient
So what is the best solution for this problem?
Or may be I should use shared_ptr instead of unique_ptr?
That depends on whether you require deep copies or are okay with shallow copies (meaning changes to one will also be visible in the other).
However,. the copy constructor of the BarContainer is problematic. It will the call copy constructor of FooContainer, that will go agead and copy only the Foo part instead of whole Bar.
The usual fix is to give your base class a virtual method clone:
class Foo {
public:
Foo(Foo&&) = default;
Foo& operator=(Foo&&) = default;
virtual ~Foo() = 0;
virtual std::unique_ptr<Foo> clone() const = 0;
protected: // or public if appropriate
Foo(const Foo&);
Foo& operator=(const Foo&);
};
class Bar : public Foo {
public:
virtual std::unique_ptr<Foo> clone() const;
};
std::unique_ptr<Foo> Bar::clone() const {
return make_unique<Bar>(*this);
}
If Foo is not abstract, it would also have an actual implementation of clone().
FooContainer::FooContainer(const FooContainer& fc)
{
many.reserve(fc.many.size());
for (auto const& fptr : fc.many)
many.emplace_back(fptr->clone());
}
I've used a template function make_unique, which was accidentally forgotten from the C++11 Standard, but will be official soon. If your compiler doesn't have one, it's simple to put your own in some header file:
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&& ... args) {
return std::unique_ptr<T>( new T(std::forward<Args>(args)...) );
}
(Together, unique_ptr, make_unique, shared_ptr, make_shared, and vector finish the huge language improvement meaning you'll almost never need the low-level and dangerous new or delete keywords again.)
Related
I am aware of the lack of reflection and basic template mechanics in C++ so the example below can't work. But maybe there's a hack to achieve the intended purpose in another way?
template <typename OwnerClass>
struct Template
{
OwnerClass *owner;
};
struct Base
{
virtual void funct ()
{
Template <decltype(*this)> temp;
// ...
}
};
struct Derived : public Base
{
void whatever ()
{
// supposed to infer this class and use Template<Derived>
// any chance some macro or constexpr magic could help?
funct();
}
};
In the example, Derived::whatever() calls virtual method Base::funct() and wants it to pass its own class name (Derived) to a template. The compiler complains "'owner' declared as a pointer to a reference of type 'Base &'". Not only does decltype(*this) not provide a typename but a reference, the compiler also can't know in advance that funct is called from Derived, which would require funct() to be made a template.
If funct() was a template however, each derived class needs to pass its own name with every call, which is pretty verbose and redundant.
Is there any hack to get around this limitation and make calls to funct() infer the typename of the calling class? Maybe constexpr or macros to help the compiler infer the correct type and reduce verbosity in derived classes?
You should use CRTP Pattern (Curiously Recurring Template Pattern) for inheritance.
Define a base class:
struct CBase {
virtual ~CBase() {}
virtual void function() = 0;
};
Define a prepared to CRTP class:
template<typename T>
struct CBaseCrtp : public CBase {
virtual ~CBaseCrtp() {}
void function() override {
using DerivedType = T;
//do stuff
}
};
Inherit from the CRTP one:
struct Derived : public CBaseCrtp<Derived> {
};
It should work. The only way to know the Derived type is to give it to the base!
Currently, this can't be done. Base is a Base and nothing else at the time Template <decltype(*this)> is instantiated. You are trying to mix the static type system for an inheritance hierarchy inherently not resolved before runtime. This very same mechanism is the reason for not calling virtual member functions of an object during its construction.
At some point, this limitation might change in the future. One step towards this is demonstrated in the Deducing this proposal.
All over the web, as well as in Bjarne Stroustrup's C++ book, I see statements like, "If a base destructor is declared virtual then it is overridden by a derived class's destructor."
But, why is it called overriding? Isn't it slightly different than the "usual" way of overriding functions? By usual, I mean a typical virtual function in a derived class, sharing the same method signature as that in the base. In that usual case, either the base version or the derived version is ignored depending on the actual object pointed to by a pointer.... Let's not get into details of how overriding works in the usual sense.
But in cases of destructors, the base destructor WILL eventually be called, no matter what. Also, its name is different. Why is it then called overriding?
Why is it then called overriding?
Because it overrides the destructor of the base class.
Consider this:
struct Foo
{
~Foo() {}
};
struct Bar : Foo
{
~Bar() {} // This does not override ~Foo.
};
Foo* fptr = new Bar;
delete fptr; // ~Foo() is called.
~Bar() will be called if the pointer is Bar*.
Bar* bptr = new Bar;
delete bptr; // ~Bar() is called.
However, if you change Foo to:
struct Foo
{
virtrual ~Foo() {}
};
struct Bar : Foo
{
~Bar() {} // This overrides ~Foo.
};
then use
Foo* fptr = new Bar;
delete fptr; // ~Bar() is called.
// ~Bar() overrides ~Foo().
I know that additional initialization methods are evil, as they leave a very nasty option for having object half-constructed and as result all methods needs to check for this. But what about this situation?
class config;
class cfg_item final
{
private:
friend class config;
cfg_item(std::weak_ptr<config> owner) : owner(owner) { }
std::weak_ptr<config> owner;
}
class config final : private std::enable_shared_from_this<config>
{
public:
config()
{
items.emplace(std::make_shared<cfg_item>(weak_from_this())); // Will crash!
}
private:
std::vector<std::shared_ptr<cfg_item>> items;
}
int main(int argc, char * argv[])
{
std::shared_ptr<config> cfg = std::make_shared<config>();
}
I KNOW WHY IT CRASHES. The std::shared_ptr in the main is not yet initialized with shared pointer to config instance, so constructor does not know how to make weak_from_this and just raises std::bad_weak_ptr exception because there are no valid std::shared_ptr pointing to this at constructor's call time.
The question is: how can I avoided the whole thing? I believe the only way I see would be to add separate initialization method, which is evil as I've already mentioned...
As note about real code: the constructors loads cfg_item from external source. It is assumed that all cfg_items are available for the entire lifetime of config. The weak pointers back to config are mandatory, as cfg_item must push all changes done to it back to config to save to external source
If you look at the answers to this question, there are strong arguments why an external initialization function is necessary. However, you rightfully write
I know that additional initialization methods are evil, as they leave a very nasty option for having object half-constructed and as result all methods needs to check for this.
it's possible to reduce this problem. Say you have a class foo, with the protocol that each time a foo object is constructed, foo::init() needs to be called. Obviously, this is a brittle class (client code will eventually omit calls to init()).
So, one way is to make the (non-copy / non-move) constructors of foo private, and create a variadic static factory method that creates objects, then calls init():
#include <utility>
class foo {
private:
foo() {}
foo(int) {}
void init() {}
public:
template<typename ...Args>
static foo create(Args &&...args) {
foo f{std::forward<Args>(args)...};
f.init();
return f;
}
};
In the following code
template<typename ...Args>
static foo create(Args &&...args) {
foo f{std::forward<Args>(args)...};
f.init();
return f;
}
note that this single method can be used for all constructors, regardless of their signature. Furthermore, since it is static, it is external to the constructor, and doesn't have the problems in your question.
You can use it as follows:
int main() {
auto f0 = foo::create();
auto f1 = foo::create(2);
// Next line doesn't compile if uncommented
// foo f2;
}
Note that it's impossible to create an object without this method, and the interface doesn't even contain init.
Consider this class:
template<typename T> struct pooled_resource: T{
template<typename... Args> pooled_resource(std::list<T>& pool, Args&&... args):
T(select_resource(pool, std::forward<Args>(args)...)), pool(pool){
if(!pool.empty()) pool.pop_front();
}
~pooled_resource(){
pool.push_front(static_cast<T&&>(*this));
}
private:
std::list<T>& pool;
template<typename... Args> static T select_resource(std::list<T>& pool, Args&&... args){
if(pool.empty())
return T(std::forward<Args>(args)...);
else
return std::move(pool.front());
}
};
It allows to create variables that have pooled resources but are semantically equivalent to the non-pooled version:
std::list<std::vector<int>> pool;
using pooled_vector = pooled_resource<std::vector<int>>;
{
pooled_vector a(pool); //pool is empty, allocate new resources
{ pooled_vector b(pool, 100); } //allocate again, but then release to pool as b goes out of scope
pooled_vector c(pool); //reuse b's resources
assert(c.size() == 100);
}
My actual problem is that for the simple case above, everything works and the move constructor of the pooled resource is called. However, I'm getting for another class that the move constructor is not called, but rather the copy constructor is. Precisely, the class is boost::compute::vector, that does declare a move constructor which seems to work in simple cases such as boost::compute::vector<int> a; boost::compute::vector<int> b(std::move(a));.
I have no clue why this happens and I don't know how to diagnose it: what am I missing regarding the rules for a move constructor to be actually used?
So the problem was a silly mistake in the class of the pooled resource. This is a sketch of it:
template<typename T, typename Allocator = DefaultAllocator> struct Resource{
/*...*/
Resource(Resource<T>&& o){ /*...*/ }
}
The problem was that the argument of the move constructor is of type Resource<T, DefaultAllocator>. Since I was using some custom allocator, there was actually no template move constructor available with a generic Allocator, but just with a generic type T and allocator DefaultAllocator. The fix just requires leaving out all template specifications of the move constructor:
Resource(Resource&& o){ /*...*/ }
Hope this can save somebody's else afternoon.
While sending stl container by reference it's not as safe as may be.
Does it make sense to wrap stl container by smart pointer to send as function argument?
template <typename T>
void f(const std::unique_ptr<T> up) {
...
}
std::unique_ptr<std::vector<char>> array;
f(std::move(array));
UPD: OK, let's narrow the question.
I'm making an instance of some class. I should construct it with a container:
class MyClass {
public:
MyClass(const std::vector<int>& ar) : m_ar(ar) {};
private:
std::vector<int> m_ar;
};
std::vector<int> tmp_ar;
tmp_ar.push_back(0);
tmp_ar.push_back(1);
tmp_ar.push_back(2);
MyClass mc(tmp_ar);
I do not want to copy a container while sending it to the constructor, then I use reference to a local variable.
Something in this code makes me nervous.
I do not want to copy a container while sending it to the constructor, then I use reference to a local variable. Something in this code makes me nervous.
The code is correct as a copy of tmp_ar is being made by m_ar(ar): mc has no reference to the local variable tmp_ar so there is no lifetime dependency between mc and tmp_ar. Problems can arise if an object stores a reference to another object and attempts to use that reference when the other object has been destructed (see dangling pointer, same applies to reference).
The tmp_ar could be std::move()d instead to avoid the copy if tmp_ar is no longer required after it has been passed as constructor argument:
class MyClass {
public:
MyClass(std::vector<int> ar) : m_ar(std::move(ar)) {};
private:
std::vector<int> m_ar;
};
std::vector<int> tmp_ar {0, 1, 2};
// Use 'tmp_ar' ...
MyClass mc(std::move(tmp_ar));