After a lot of research I still don't understand how to deal with an abstract class collection with smart pointers.
Here are the errors I got:
error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Shape; _Dp = std::default_delete<Shape>]'
base_ptr s = shapes.front();
error: no matching function for call to 'std::unique_ptr<Shape>::unique_ptr(Shape&)'
shapes.push(base_ptr(b));
By compiling the minimal code to replicate the error (code online avaiable).
#include <queue>
#include <memory>
class Shape {
public:
virtual int getPerimeter() =0;
};
typedef std::unique_ptr<Shape> base_ptr;
class Circle : public Shape {
public:
virtual int getPerimeter() { return 1; };
};
class Square : public Shape {
public:
virtual int getPerimeter() { return 0; };
};
class ShapeManager {
public:
ShapeManager();
void useShape() {
if(shapes.empty())
throw "Work stack is empty.";
base_ptr s = shapes.front();
s->getPerimeter();
shapes.pop();
}
void submitShape(Shape &b) {
shapes.push(base_ptr(b));
}
private:
std::queue<base_ptr> shapes;
};
int main(int argc, char **argv) {
ShapeManager s();
Circle c;
s.submitShape(c);
s.useShape();
return 1;
}
It works if I declare the queue as queue<Shape*> but I don't want to deal with pointers -meaning *.
EDIT, this code compiles. Thanks everyone. This article suggested by Guillaume Racicot helps seeing clearer the situation.
#include <queue>
#include <memory>
class Shape {
public:
virtual int getPerimeter() =0;
};
typedef std::unique_ptr<Shape> base_ptr;
class Circle : public Shape {
public:
Circle() {};
virtual int getPerimeter() { return 1; };
};
class Square : public Shape {
public:
virtual int getPerimeter() { return 0; };
};
class ShapeManager {
public:
ShapeManager();
void useShape() {
if(shapes.empty())
throw "Work stack is empty.";
base_ptr s = std::move(shapes.front());
s->getPerimeter();
shapes.pop();
}
void submitShape(base_ptr b) {
shapes.push(std::move(b));
}
private:
std::queue<base_ptr> shapes;
};
int main(int argc, char **argv) {
ShapeManager s;
base_ptr c = std::make_unique<Circle>();
s.submitShape(std::move(c));
s.useShape();
return 1;
}
The container is a distraction. The problem is that unique_ptr is not copyable; if it were, it wouldn't be unique. So you probably need to add a call to std::move:
base_ptr s = std::move(shapes.front());
This means something different from what the original code might have been intended to do; it removes the object from the container. If that's not what you wanted, then std::move isn't the right answer and, probably, unique_ptr is not the right mechanism.
There are many problems in your example, not just misuse of smart pointers. First, the most obvious once is your declaration of s:
ShapeManager s();
This declares a function named s that returns a ShapeManager and takes no parameter.
Maybe you meant to declare an object of type ShapeManager?
ShapeManager s{};
// Or
ShapeManager s;
Secondly, you are misusing smart pointer. You have a queue of unique pointer. A unique pointer is a RAII wrapper around a free store allocated object. That means that it's a wrapper that is constructed with an object allocated with new. In your example, you're not doing that. You are constructing unique pointer with an object that has automatic storage.
A smart pointer that points to a automatic storage allocated object is the observer pointer: is must not own, delete or try to manage anything about that object. In fact, observer pointer is a language feature instead of a library one. It's commonly called a pointer.
This is your code with usage of observer pointers:
template<typename T>
using observer_ptr = T*;
struct ShapeManager {
void useShape() {
if(shapes.empty())
throw "Work stack is empty.";
auto s = shapes.front();
s->getPerimeter();
shapes.pop();
}
void submitShape(Shape &b) {
shapes.push(&b);
}
private:
std::queue<base_ptr> shapes;
};
int main() {
ShapeManager s;
Circle c; // Automatic storage
Rectangle r; // Automatic storage too.
s.submitShape(c);
s.submitShape(r);
s.useShape();
}
However, you might not want to hold them using automatic storage. My guess is you want to use std::unique_ptr everywhere instead. This allow the object submitted to the shape manager to outlive it's scope. For that you'll need to allocate objects on the free store. The most common way is to use std::make_unique:
struct ShapeManager {
void useShape() {
if(shapes.empty())
throw "Work stack is empty.";
// We must create a reference,
// Using simply auto would require copy,
// Which is prohibited by unique pointers
auto&& s = shapes.front();
s->getPerimeter();
shapes.pop();
}
void submitShape(base_ptr b) {
shapes.push(std::move(b));
}
private:
std::queue<base_ptr> shapes;
};
int main() {
ShapeManager s;
// Allocated on the free store,
// The lifetime of c and r are managed by
// The unique pointer.
auto c = std::make_unique<Circle>();
auto r = std::make_unique<Rectangle>();
s.submitShape(std::move(c));
s.submitShape(std::move(r));
s.useShape();
}
Related
I am trying to code two classes FooFactory and Foo. FooFactory initializes an object ToolBox in the constructor and stores it in a unique_ptr as I want that to be cleaned after the factory is destructed. All the instances of Foo should be able to use ToolBox so I am passing ptr to ToolBox object in the constructor of Foo and storing it as bare ptr.
I am new to c++ development so, my questions in the light of general suggestion I heard :
avoid raw pointers when possible
Is the usage of bare ptr to store the tool_box object that Foo doesn't own fine in this case? or Can I do better using smart_ptr?
Is the pattern of passing the ptr to ToolBox from the FooFactory class to every new object the correct or is there something better I can do?
Pseudo-code for my classes:
class FooFactory {
public:
FooFactory() {
tool_box_.reset(new ToolBox());
}
std::unique_ptr<Foo> NewFoo() {
std::unique_ptr<Foo> foo(new Foo(tool_box_.get());
return foo;
}
std::unique_ptr<ToolBox> tool_box_;
}
class Foo {
public:
Foo(ToolBox* tool_box) {
tool_box_ = tool_box;
}
private:
// Not Owned
ToolBox* tool_box;
}
A factory would normally never control the lifetime of an object. It should hand out an appropriate pointer, preferably a std::unique_ptr and the caller determines it's lifetime.
#include <string>
#include <iostream>
#include <memory>
class Box
{
public:
Box() {}
};
class Foo
{
public:
Foo(std::shared_ptr<Box> &box)
: m_box(box)
{
}
virtual ~Foo(){}
void print()
{
std::cout << "Hello World" << std::endl;
}
protected:
Box *getBox()
{
return m_box.get();
}
private:
std::shared_ptr<Box> m_box;
};
class FooFactory
{
public:
FooFactory()
{
m_box = std:make_shared<Box>();
}
std::unique_ptr<Foo> CreateFoo()
{
return std::make_unique<Foo>(m_box);
}
private:
std::shared_ptr<Box> m_box;
};
int main()
{
FooFactory factory;
std::unique_ptr<Foo> foo = factory.CreateFoo();
foo->print();
return 0;
}
One way to store a non-owning "pointer" to an object (while coupling the class with that object) would be to store a reference (or perhaps a const reference) instead of a pointer.
In my experience, the constraint of needing to initialize the class with that reference helps hierarchical design and simplifies lifetime management.
My c++ code has to work with an underlying c-library. I have a c++ object that looks somewhat like this:
template <typename T>
class MyClass
{
public:
explicit MyClass(int x)
: mVar(x)
{
}
private:
int mVar;
};
Later in my c++ code I do the following:
auto p = new MyClass<int>(10);
call_c_lib_function((void*) p);
The c function saves the pointer 'p' in a larger c-structure. Later when the large
c object is getting destroyed, it invokes the delete handler.
void
c_delete_handler(void* data)
{
// data is holding the pointer value 'p' from above.
}
Since the object is getting destroyed, I need to free the object that allocated.
Per the c++ spec, 'delete void_ptr' is undefined since it doesn't know how to
invoke the appropriate destructor. How do I invoke delete on the appropriate
template object?
One solution I could think of was to create a wrapper structure around my MyClass pointer.
struct Wrapper {
enum template_type {
template_int,
template_double,
template_string,
...
};
int template_type;
void* obj_ptr;
};
before callign the call_c_lib_function, I'd do the following:
auto p = new MyClass<int>(10);
auto w = new Wrapper()
w.template_type = Wrapper::template_int;
w.obj_ptr = (void*) p;
call_c_lib_function((void) w);
and now in the delete handler, I can do the following:
void
c_delete_handler(void* data)
{
Wrapper* w = (Wrapper*) data;
switch (w->template_type) {
case Wrapper::template_int:
delete (MyClass<int>*) w->obj_ptr;
break;
case Wrapper::template_double:
delete (MyClass<double>*) w->obj_ptr;
break;
...
}
}
Is this a correct approach? is there a better alternative?
Would appreciate any inputs. Thanks.
Instead of using Wrapper, use a base class, if that's an option.
class MyBase
{
public:
virtual ~MyBase() {};
};
template <typename T>
class MyClass : public MyBase
{
public:
explicit MyClass(int x) : mVar(x) {}
private:
int mVar;
};
and then
void c_delete_handler(void* data)
{
Base* basePtr = reinterpret_cast<Base*>(data);
delete basePtr;
}
This approach obviates the need for keeping track of whether MyClass was instantiated using int, double, std::string, or ....
What I did: I recently started to write a multi-threaded producer-consumer-style queue. Initially, I went with smart pointers but ended up changing all of them to raw pointers and managing their lifetime and their memory management manually (code at the end, if interested).
What I'm looking for: arguments for or against this conjecture:
Inheritance can't sit in the same room as shared pointers, as nicely as it would with raw pointers and reference objects.
My Reasoning:
Base and Derived objects are covariant. So are raw pointers (Base* and Derived*). Shared pointers (shared_ptr<Base> and shared_ptr<Derived>) are not.
The programmer has to do many conceptually unnecessary downcasting using dynamic_pointer_cast, which makes the code ugly and are somewhat expensive at compile time and run time.
This makes me wonder if shared pointers should be avoided in object-oriented designs, as their benefits do not overweigh their expense and headache.
My code before change (multi-threading is left out for the sake of readability):
typedef shared_ptr<Animal> animal_ptr;
typedef shared_ptr<Dog> dog_ptr;
class Buffer {
private:
mutex mu_;
condition_variable cond_;
deque<shared_ptr<Animal> > buffer_;
public:
void add(shared_ptr<Animal> req) {
std::unique_lock<std::mutex> locker(mu_);
cond_.wait(locker, [this](){return buffer_.size() < size_;});
buffer_.push_back(req);
locker.unlock();
cond_.notify_all();
}
shared_ptr<Animal> remove() {
unique_lock<mutex> locker(mu_);
cond_.wait(locker, [this](){return buffer_.size() > 0;});
shared_ptr<Animal> back = buffer_.back();
buffer_.pop_back();
locker.unlock();
cond_.notify_all();
}
};
int main() {
Buffer buffer;
animal_ptr bPtr1 (new Animal()); // buffer.add() works just fine
dog_ptr dPtr1 (new Dog()); // EDIT: works fine too.
animal_ptr dptr2 (new Dog()); // EDIT: it's okay
...
buffer.remove(); // returns a base class object, requires downcasting to access derived members
}
EDIT for more clarification, and why shared pointers are treating inheritence differently than raw pointers:
void func1(shared_ptr<Animal> ptr);
void func2(Animal* ptr);
...
Dog* rawPtr = new Dog();
func1(dPtr1); // is not possible, requires upcasting
func2(rawPtr); // is ok.
No, it works.
http://coliru.stacked-crooked.com/a/b2a83c740ed60521
#include <iostream>
#include <memory>
struct A {
void print() { std::cout << "A" << std::endl; }
};
struct B : public A {
void print() { std::cout << "B" << std::endl; }
};
void print(std::shared_ptr<A> a) {
a->print();
}
int main() {
std::shared_ptr<A> ptr_a(new A);
std::shared_ptr<B> ptr_b(new B);
ptr_a->print();
ptr_b->print();
ptr_b->A::print();
//THIS WORKS!
print(ptr_a);
print(ptr_b);
}
The last two "A" print correctly. The reason your function doesn't work is because Dog* != std::shared_ptr<Dog>.
std::shared_ptr<derived> is implicitly convertible to std::shared_ptr<base>, so you should have no errors in passing a derived pointer to a function that takes a base pointer unless you are using a bad compiler.
An example function that compiles fine:
class animal{
public:
virtual auto print() const -> void = 0;
};
class dog: public animal{
public:
auto print() const -> void{ std::cout << "I'm a Dog!\n"; }
};
class cat: public animal{
public:
auto print() const -> void{ std::cout << "I'm not a Dog!\n"; }
};
auto func(std::shared_ptr<animal> ptr){
ptr->print();
}
auto main() -> int{
auto dog_ptr = std::make_shared<dog>();
auto cat_ptr = std::make_shared<cat>();
func(dog_ptr);
func(cat_ptr);
}
Will print:
I'm a Dog!
I'm not a Dog!
Now I understand the problems that you are having. If you consistently use shared_ptr everywhere, you are able to pass shared_ptr objects of Base and Derived the same as raw pointers. I fleshed out the example that you gave.
The problem comes when you mix shared_ptr and raw pointers. The first problem goes away with overloading, where the shared_ptr function forwards to the function taking a raw pointer where the real work is done. The second problem goes away when calling with the underlying raw pointer obtained from the shared pointer.
class Animal
{
public:
};
class Dog : public Animal
{
public:
};
using std::shared_ptr;
typedef shared_ptr<Animal> animal_ptr;
typedef shared_ptr<Dog> dog_ptr;
class Buffer {
private:
std::deque<shared_ptr<Animal> > buffer_;
public:
void add(shared_ptr<Animal> req) {
buffer_.push_back(req);
}
shared_ptr<Animal> remove() {
shared_ptr<Animal> back = buffer_.back();
buffer_.pop_back();
}
};
void func1(Animal* ptr)
{}
void func1(shared_ptr<Animal> ptr)
{
func1(ptr.get());
}
void func2(Animal* ptr)
{}
int main()
{
Buffer buffer;
animal_ptr bPtr1(new Animal()); // buffer.add() works just fine
dog_ptr dPtr1(new Dog()); // requires upcasting before buffer.add()
animal_ptr dptr2(new Dog()); // returns error, as they are covariant
Dog* rawPtr = new Dog();
func2(rawPtr); // is ok.
func1(dPtr1); // is ok.
func1(rawPtr); // requires overloading func1 with shared_ptr and raw pointer signatures
func2(dPtr1.get()); // is okay when using underlying raw ptr
return 0;
}
I would like to write a function that can initialize and return objects of different classes using polymorphism. I also would like these classes to have different data members which may be called through the virtual function. What I wrote below might work. Could you check if I have some undefined behavior in there? Thank you! One thing I am worried about is that when I call "delete polypoint" at the end it will not free the data member "scale" that is unique to "CRectangle". If my code doesn't work is there a way to make it work?
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area ()
{ return (0); }
};
class CRectangle: public CPolygon {
public:
int scale;
int area ()
{ return (width * height * scale ); }
};
CPolygon *polytestinner()
{
CPolygon *polypoint = 0;
int consoleinput = 2;
if (consoleinput>1)
{
CRectangle *rectpoint = new CRectangle();
rectpoint->scale = 4;
polypoint = rectpoint;
}
polypoint->set_values(3,4);
return polypoint;
}
void polytest()
{
CPolygon *polypoint = polytestinner();
gstd::print<int>(polypoint->area());
delete polypoint;
}
int main()
{
polytest();
return 0;
}
Thank you!
I feel compelled to point out Andrei Alexandrescu's object factory architecture. It allows your architecture to grow without having to modify the factory every time you create a concrete type. It is based on a "callback register", and it is actually implemented as a generic component in some libraries. The code is below.
Live Code Example
#include<map>
#include<iostream>
#include<stdexcept>
// your typical base class
class Shape {
public:
virtual void Draw() const = 0;
// virtual destructor allows concrete types to implement their own
// destrucion mechanisms
virtual ~Shape() {}
};
// this factory architecture was suggested by Andrei Alexandrescu in
// his book "Modern C++ Design" --- read it to get the full
// explanation (and a more generic implementation); this is just an
// example
class ShapeFactory {
public:
// this typedef allows to "name" arbitrary functions which take no
// arguments and return a pointer to a Shape instance
typedef Shape* (*CreateShapeCallback)();
Shape* CreateShape(int ShapeId) {
// try to find the callback corresponding to the given shape id;
// if no shape id found, throw exception
CallbackMap::const_iterator it = m_callbacks.find(ShapeId);
if(it == m_callbacks.end()) {
throw std::runtime_error("unknown shape id");
} else {
// create the instance using the creator callback
return (it->second)();
}
}
bool RegisterShape(int ShapeId, CreateShapeCallback Creator) {
// returns true if shape was registered; false if it had already
// been registered
return m_callbacks.insert(CallbackMap::value_type(ShapeId, Creator)).second;
}
bool UnRegisterShape(int ShapeId) {
// returns true if shape was unregistered, false if it was not
// registered in the first place
return m_callbacks.erase(ShapeId) == 1;
}
private:
// the typedef simplifies the implementation
typedef std::map<int, CreateShapeCallback> CallbackMap;
// the callbacks are stored in a map int->callback (see typedef
// above)
CallbackMap m_callbacks;
};
// create some concrete shapes... you would do this in other CPP files
class Line : public Shape {
public:
void Draw() const {
std::cout<<"Drawing a line"<<std::endl;
}
};
// another concrete shape...
class Circle : public Shape {
public:
void Draw() const {
std::cout<<"Drawing a circle"<<std::endl;
}
};
// ... other concrete shapes...
enum ShapeIds {LINE=1, CIRCLE, COUNT};
Shape* CreateLine() { return new Line; }
Shape* CreateCircle() { return new Circle; }
int main() {
// suppose this is the "singleton" instance for the ShapeFactory
// (this is an example! Singletons are not implemented like this!)
ShapeFactory *factory = new ShapeFactory;
factory->RegisterShape(ShapeIds::LINE, CreateLine);
factory->RegisterShape(ShapeIds::CIRCLE, CreateCircle);
Shape* s1 = factory->CreateShape(ShapeIds::CIRCLE);
Shape* s2 = factory->CreateShape(ShapeIds::LINE);
s1->Draw();
s2->Draw();
// will throw an error
try {
Shape *s3 = factory->CreateShape(-1);
s3->Draw();
} catch(const std::exception& e) {
std::cout<<"caught exception: "<<e.what()<<std::endl;
}
return 0;
}
CPolygon needs a virtual destructor:
virtual ~CPolygon() {}
You have undefined behavior in your code:
CPolygon *polypoint;
delete polypoint;
deleting a base class pointer when there is no virtual destructor will result in undefined behavior.
Your CPolygon class and CRectangle classes have no destructors, though the compiler will generate default destructor for you in this case, but they are not virtual by default. Therefore, you need to at least define a virtual destructor for your base class, i.e., CPolygon.
I'd like to be able to call some member functions from different classes which all have the same general syntax and base class. Something along the lines of
class A: public BaseClass
{
public:
A();
~A();
int DoFoo();
int DoBar();
int DoBarBar();
};
class B : public BaseClass
{
public:
B();
~B();
int DoSomething();
int DoSomethingElse();
int DoAnother();
};
Where I could potentially places the member functions from both classes into one map so that I could have something like
key value
"Option1" *DoFoo()
"Option2" *DoSomething()
"Option3" *DoFoo()
... ...
"Option6" *DoAnother()
Where I could call a function to return a value based on what option I chose, regardless of what class the function belongs to.
Through some searching, I tried to implement my own mapped set of functors. However, the map retains the address of the functor, but the functions within become null.
Here are my functor declarations which store a class object and a function pointer
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
//////////////////////////////////////////////////////////////
//Functor Classes
//////////////////////////////////////////////////////////////
class TFunctor
{
public:
virtual void operator()()=0; // call using operator
virtual int Call()=0; // call using function
};
// derived template class
template <class TClass> class TSpecificFunctor : public TFunctor
{
private:
int (TClass::*fpt)(); // pointer to member function
TClass* pt2Object; // pointer to object
public:
// constructor - takes pointer to an object and pointer to a member and stores
// them in two private variables
TSpecificFunctor(TClass* _pt2Object, int(TClass::*_fpt)())
{ pt2Object = _pt2Object; fpt=_fpt; };
// override operator "()"
virtual void operator()()
{ (*pt2Object.*fpt)();}; // execute member function
// override function "Call"
virtual int Call()
{return (*pt2Object.*fpt)();}; // execute member function
};
typedef std::map<std::string, TFunctor*> TestMap;
//////////////////////////////////////////////////////////////
//Test Classes
//////////////////////////////////////////////////////////////
//Base Test class
class base
{
public:
base(int length, int width){m_length = length; m_width = width;}
virtual ~base(){}
int area(){return m_length*m_width;}
int m_length;
int m_width;
};
//Inherited class which contains two functions I would like to point to
class inherit:public base
{
public:
inherit(int length, int width, int height);
~inherit();
int volume(){return base::area()*m_height;}
int area2(){return m_width*m_height;}
int m_height;
TestMap m_map;
};
where my inherit class constructor looks like:
inherit::inherit(int length, int width, int height):base(length, width)
{
m_height = height;
TSpecificFunctor<inherit> funcA(this, &inherit::volume);
m_map["a"] = &funcA;
TSpecificFunctor<inherit> funcB(this, &inherit::area2);
m_map["b"] = &funcB;
}
Which is where I am mapping two functions into a map. Things still look okay in the above function in terms of memory address and function pointers.
I then try to create an instance of inherit in a new class...
class overall
{
public:
overall();
~overall(){}
inherit *m_inherit;
TestMap m_mapOverall;
};
overall::overall()
{
m_inherit = new inherit(3,4,5);
TestMap tempMap = m_inherit->m_map;
int i = 0;
}
Here when I look at the values of m_inherit->m_map, I notice that the keys are still consistent, however the memory addresses of the functions which I tried to point to have disappeared.
I haven't had much experience with functors but from my understanding, it is able to retain states, which I assume means that I can call member functions outside of its class. But I'm starting to think that my member functions disappear because it is out of scope.
You are right, it is a scooping issue. In the inherit constructor, funcA and funcB are both allocated on the stack and destroyed once the function goes out of scope. The leaves m_map with stale pointers.
What you really want is something like
inherit::inherit(int lenght, int width, int height) :base(length, width)
{
m_height = height;
// allocated on the heap
TSpecificFunctor<inherit> * funcA = new TSpecificFunctor<inherit>(this, &inherit::volume);
m_map["a"] = funcA;
// allocated on the heap
TSpecificFunctor<inherit> * funcB = new TSpecificFunctor<inherit>(this, &inherit::area2);
m_map["b"] = funcB;
} // when this function exits funcA and funcB are not destroyed
But, to avoid any memory leaks, the destructor for inherit will need to clean up the values
inherit::~inherit()
{
for(TestMap::iterator it = m_map.begin(); it != m_map.end(); ++it) {
delete it->second;
}
}
Using new and delete can easily lead to memory leaks. To prevent them, I would suggest looking into smart points like std::unique_ptr and std::shared_ptr. Also, functors are becoming obsolete with the introduction of lambdas in C++11. They are really neat and worth looking into if you are not familiar with them.
If your compiler supports them, to do this with lambdas
#include <functional>
// ...
typedef std::map<std::string, std::function<int(void)>> TestMap;
// ...
inherit::inherit(int length, int width, int height):base(length, width)
{
m_height = height;
m_map["a"] = [this]() -> int { return volume(); };
m_map["b"] = [this]() -> int { return area2(); };
// can be called like so
m_map["a"]();
m_map["b"]();
}
// No need to clean up in destructors
You're right - the TSpecificFunctors go out of scope at the end of inherit's constructor, so you shouldn't keep pointers to them.
If you can, prefer smart pointers, e.g.
#include <memory>
...
typedef std::map<std::string, std::shared_ptr<TFunctor>> TestMap;
...
inherit::inherit(int length, int width, int height):base(length, width)
{
m_height = height;
m_map["a"] = std::shared_ptr<TSpecificFunctor<inherit>>(
new TSpecificFunctor<inherit>(this, &inherit::volume));
m_map["b"] = std::shared_ptr<TSpecificFunctor<inherit>>(
new TSpecificFunctor<inherit>(this, &inherit::area2));
}
Your main concern then is to ensure that the functors in m_inherit->m_map are not invoked after m_inherit is destroyed or you will get undefined behaviour. In this case, you're safe since you leak m_inherit (it's never destroyed).