I'm implementing a math library in C++. The library will be compiled to a DLL so those who use it will only need the header files the classes' definitions.
The users of my classes will be people who are new to the language. However, there are some objects that might be referenced in several parts of their programs. Since I don't expect them to do the memory management, I'd like to do it myself. Therefore, I have to implement reference counting (garbage collection is not a possibility).
I want to make that reference counting as transparent as possible, for example...
// Define a Bézier curve
CVecList pts;
pts.Add(Vector(0,0,0));
pts.Add(Vector(0,0,100));
pts.Add(Vector(0,100,0));
pts.Add(Vector(0,100,100));
CCurve* c1 = new CBezier(pts);
// Define a 3rd order B-Spline curve
pts.Clear();
pts.Add(Vector(0,0,0));
pts.Add(Vector(0,200,100));
pts.Add(Vector(0,200,200));
pts.Add(Vector(0,-200,100));
pts.Add(Vector(0,-200,200));
pts.Add(Vector(0,0,0));
CCurve* c2 = new CBSpline(pts,3);
// The Bézier curve object must be deleted automatically
// because the only reference to it has been released
// Similar to IUnknown::Release() in COM
c1 = c2;
Things get a little bit more tricky when I define surface objects, because some surfaces are defined in terms of two curves:
CVecList pts;
// ...
CCurve* f = new CBezier(pts);
pts.Clear();
// ...
CCurve* g = new CBezier(pts);
// Mixed surface: S(u,v) = (1-v)*f(u) + v*g(u)
CSurface* s = new CMixed(f,g);
// There are two references to the first Bézier curve,
// the first one is f
// the second one is hidden in a member of CMixed
// Something similar applies to the second Bézier curve
I thought that overriding operator = for pointers could have helped:
// This is what I tried, but it's illegal:
typedef CReferenceCounted* PRC;
PRC& operator =(PRC& dest, PRC& source)
{
if (source)
source->AddRef();
if (dest)
dest->Release();
memcpy(&dest,&source,sizeof(PRC));
return dest;
}
... but then I found that operator = is not valid unless it is as a non-static member of a class.
Could anybody possible help me?
What you tried was to overload an operator for scalar types. C++ doesn't allow you to do that except for enumerations (beside the point that operator= has to be a member). At least one of the types has to be a user defined type. Thus, what you want to do is to wrap the raw pointer into a user defined class, which overloads constructor, copy constructor, copy assignment operator and destructor an do the proper reference counting. This is an ideal situation for boost::shared_ptr, which does exactly that :
boost::shared_ptr<CCurve> c1(new CBezier(pts));
The same deal with surfaces:
CVecList pts;
// ...
boost::shared_ptr<CCurve> f(new CBezier(pts));
pts.Clear();
// ...
boost::shared_ptr<CCurve> g(new CBezier(pts));
// Mixed surface: S(u,v) = (1-v)f(u) + vg(u)
boost::shared_ptr<CSurface> s(new CMixed(f,g));
Carry around that smart pointer, and it will automatically manage the life-time of the pointed to object: If the last copy of the pointer goes out of scope, the object pointed to is freed. shared_ptr is designed to be easy to use. Try to avoid working with raw pointers as much as you can. Have a look at those smart pointers, they will ease your programmers live with C++ :)
Edit: If you are going to wrap a shared_ptr, you can do so using the pimpl (handle/body) idiom:
/* ---- wrapper in header file bezier.hpp */
struct CBezier {
CBezier(CVecList const& list);
void do_calc();
// ...
private:
struct CBezierImpl;
boost::shared_ptr<CBezierImpl> p;
};
/* ---- implementation file bezier.cpp */
// private implementation
struct CBezier::CBezierImpl {
CBezierImpl(CVecList const& list);
void do_calc();
// ...
};
CBezier::CBezier(CVecList const& list)
:p(new CBezierImpl(list)) {
}
void CBezier::do_calc() {
// delegate to pimpl
p->do_calc();
}
// ...
If you're designing a math library, spend a lot of time thinking whether your classes can look like int or std::complex. That is to say, have values behave like values. E.g.
std::vector<math::point3d> pts;
pts.push_back(math::point3d(0,0,0));
pts.push_back(math::point3d(110,0,0));
pts.push_back(math::point3d(0,100,0));
pts.push_back(math::point3d(0,0,100));
CCurve c1 = make_bezier(pts);
I'd recommend intrusive_ptr instead of shared_ptr for objects you can control for better performance and usability, as you can assign a raw pointer to intrusive_ptr later, because the reference count is embedded in the object.
The users of my classes will be people who are new to the language.
Is your class designed for a programing course ?
If this is the case, I would avoid using pointers and use only copy constructors / assignation:
Performance / Memory is not a priority
Doing the memory management yourself will show a pretty bad example on how to use new/delete
Using any kind of smart pointer without knowing about memory management could cause a lot of confusion later on.
I agree with Guishu and MSalters. Even if it's not for a programming course, it may be nice to imitate more closely maths look (e.g. vector3 = vector1+vector2 etc).
What you could also do is to use copy-on-write (refounting being a logical consequence), but only internally. That may give you fast-enough assignments, eliminate heap management on the client-side and similarity to math notation.
Note, however, that there are math libraries available for C++ (TNT, off the top of my head). Did you consider basing your work on that?
Related
I'm quite far into the development of a game using SDL, OpenGL and C++ and am looking for ways to optimize the way the game switches between GLSL shaders for lots of different objects of different types. This is much more of a C++ question than an OpenGL question. However, I still want to provide as much context as I can, as I feel some justification is needed as to why the proposed Shader class I need, needs to be created / deleted the way that it is.
The first four sections are my justifications, journey & attempts leading up to this point, however my question can likely be answered by just the final section alone and I've intentionally written it as a bit of a tldr.
The necessity for a Shader class:
I've seen many implementations online of OpenGL shaders being created, compiled and deleted all in the same function when game objects are created during gameplay. This has proven to be inefficient and far too slow in particular sections of my game. Thus, I've required a system that creates and compiles shaders during a load-time and then intermittently uses/swaps between them during game-time before being deleted later.
This has lead to the creation of a class(Shader) that manages OpenGL shaders. Each instance of the class should manage one unique OpenGL shader each and contains some complex behavior around the shader type, where it's loaded in from, where it's used, the uniform variables it takes, etc.
With this said, the most important role of this class is to store the GLuint variable id that is returned from glCreateShader(), and manage all OpenGL calls that relate to the OpenGL shader with this id. I understand that this is effectively futile given the global nature of OpenGL(as anywhere in the program could technically call glDeleteShader() with the matching id and break the class), however for the purposes of intentionally encapsulating all OpenGL calls to very specific areas throughout the entire codebase this system will drastically reduce code-complexity.
Where the problems start...
The most "automatic" way to manage this GLuint id, would be to invoke glCreateShader() on the object's construction and glDeleteShader() on the object's destruction. This guarantees(within OpenGL limits) that the OpenGL shader will exist for the entire lifetime of the C++ Shader object and eliminates the need to call some void createShader() and deleteShader() functions.
This is all well and good, however problems soon arise when considering what happens if this object is copied. What if a copy of this object is destructed? That means that glDeleteShader() will be called and effectively break all copies of the shader object.
What about simple mistakes like accidentally invoking std::vector::push_back() in a vector of Shaders? Various std::vector methods can invoke the constructor / copy constructor / destructor of their type, which can result in the same problem as above.
Okay then... how about we do create some void createShader() and deleteShader() methods even if it's messy? Unfortunately this just defers the above problem, as once again any calls that modify the OpenGL shader will desynchronize / outright break all copies of a shader class with the same id. I've limited the OpenGL calls to glCreateShader() and glDeleteShader() in this example to keep things simple, however I should note that there are many other OpenGL calls in the class that would make creating various instance/static variables that keep track of instance copies far too complicated to justify doing it this way.
The last point I want to make before jumping into the class design below is that for a project as large as a raw C++, OpenGL and SDL Game, I'd prefer if any potential OpenGL mistakes I make generate compiler errors versus graphical issues that are harder to track down. This can be reflected in the class design below.
The first version of the Shader class:
It is for the above reasons that I have elected to:
Make the constructor private.
Provide a public static create function that returns a pointer to a new Shader object in place of a constructor.
Make the copy constructor private.
Make the operator= private (Although this might not be necessary).
Make the destructor private.
Put calls to glCreateShader() in the constructor and glDeleteShader() in the destructor, to have OpenGL shaders exist for the lifetime of this object.
As the create function invokes the new keyword(and returns the pointer to it), the place with the outside call to Shader::create() must then invoke delete manually (more on this in a second).
To my understanding, the first two bullet points utilize a factory pattern and will generate a compiler error should a non-pointer type of the class be attempted to be created. The third, fourth and fifth bullet points then prevent the object from being copied. The seventh bullet point then ensures that the OpenGL Shader will exist for the same lifetime of the C++ Shader object.
Smart Pointers and the main problem:
The only thing I'm not a huge fan of in the above, is the new/delete calls. They also make the glDeleteShader() calls in the destructor of the object feel inappropriate given the encapsulation that the class is trying to achieve. Given this, I opted to:
change the create function to return a std::unique_ptr of the Shader type instead of a Shader pointer.
The create function then looked like this:
std::unique_ptr<Shader> Shader::create() {
return std::make_unique<Shader>();
}
But then a new problem arose... std::make_unique unfortunately requires that the constructor is public, which interferes with the necessities described in the previous section. Fortunately, I found a solution by changing it to:
std::unique_ptr<Shader> Shader::create() {
return std::unique_ptr<Shader>(new Shader());
}
But... now std::unique_ptr requires that the destructor is public! This is... better but unfortunately, this means that the destructor can be manually called outside of the class, which in turn means the glDeleteShader() function can be called from outside the class.
Shader* p = Shader::create();
p->~Shader(); // Even though it would be hard to do this intentionally, I don't want to be able to do this.
delete p;
The final class:
For the sake of simplicity, I have removed the majority of instance variables, function/constructor arguments & other attributes but here's what the final proposed class (mostly)looks like:
class GLSLShader {
public:
~GLSLShader() { // OpenGL delete calls for id }; // want to make this private.
static std::unique_ptr<GLSLShader> create() { return std::unique_ptr<GLSLShader>(new GLSLShader()); };
private:
GLSLShader() { // OpenGL create calls for id };
GLSLShader(const GLSLShader& glslShader);
GLSLShader& operator=(const GLSLShader&);
GLuint id;
};
I'm happy with everything in this class, aside from the fact that the destructor is public. I've put this design to the test and the performance increase is very noticeable. Even though I can't imagine I'd ever accidentally manually call the destructor on a Shader object, I don't like that it is publicly exposed. I also feel that I might accidentally miss something, like the std::vector::push_back consideration in the second section.
I've found two potential solutions to this problem. I'd like some advice on these or other solutions.
Make std::unique_ptr or std::make_unique a friend of the Shader class. I've been reading threads such as this one, however this is to make the constructor accessible, rather than the destructor. I also don't quite understand the downsides / extra considerations needed with making std::unique_ptr or std::make_unique a friend (The top answer to that thread + comments)?
Not use smart pointers at all. Is there perhaps a way to have my static create() function return a raw pointer(using the new keyword), that is automatically deleted inside the class / when the Shader goes out of scope and the destructor is called?
Thank you very much for your time.
This is a context challenge.
You are solving the wrong problem.
GLuint id, would be to invoke glCreateShader() on the object's construction and glDeleteShader()
Fix the problem here.
The Rule of Zero is that you make your resource wrappers manage lifetimes, and you don't do it in business logic types. We can write a wrapper around a GLuint that knows how to clean itself up and is move-only, preventing double destruction, by hijacking std::unique_ptr to store an integer instead of a pointer.
Here we go:
// "pointers" in unique ptrs must be comparable to nullptr.
// So, let us make an integer qualify:
template<class Int>
struct nullable{
Int val=0;
nullable()=default;
nullable(Int v):val(v){}
friend bool operator==(std::nullptr_t, nullable const& self){return !static_cast<bool>(self);}
friend bool operator!=(std::nullptr_t, nullable const& self){return static_cast<bool>(self);}
friend bool operator==(nullable const& self, std::nullptr_t){return !static_cast<bool>(self);}
friend bool operator!=(nullable const& self, std::nullptr_t){return static_cast<bool>(self);}
operator Int()const{return val;}
};
// This both statelessly stores the deleter, and
// tells the unique ptr to use a nullable<Int> instead of an Int*:
template<class Int, void(*deleter)(Int)>
struct IntDeleter{
using pointer=nullable<Int>;
void operator()(pointer p)const{
deleter(p);
}
};
// Unique ptr's core functionality is cleanup on destruction
// You can change what it uses for a pointer.
template<class Int, void(*deleter)(Int)>
using IntResource=std::unique_ptr<Int, IntDeleter<Int,deleter>>;
// Here we statelessly remember how to destroy this particular
// kind of GLuint, and make it an RAII type with move support:
using GLShaderResource=IntResource<GLuint,glDeleteShader>;
now that type knows it is a shader and cleans itself up it non-null.
GLShaderResource id(glCreateShader());
SomeGLFunction(id.get());
apologies for any typos.
Stuff that in your class, and copy ctors are blocked, move ctors do the right thing, dtors clean up automatically, etc.
struct GLSLShader {
// public!
~GLSLShader() = default;
GLSLShader() { // OpenGL create calls for id };
private: // does this really need to be private?
GLShaderResource id;
};
so much simpler.
std::vector<GLSLShader> v;
and that just works. Our GLShaderResource is semi-regular (move only regular type, no sort support), and vector is happy with those. Rule of 0 means that GLSLShader, which owns it, is also semi-regular and supports RAII -- resource allocation is initialization -- which in turn means it cleans up after itself properly when stored in std containers.
A type being "Regular" means it "behaves like an int" -- like the prototypical value type. C++'s standard library, and much of C++, likes it when you are using regular or semi-regular types.
Note that this is basically zero overhead; sizeof(GLShaderResource) is the same as GLuint and nothing goes on the heap. We have a pile of compile-time type machinery wrapping a simple 32 bit integers; that compile-time type machinery generates code, but doesn't make the data more complex than 32 bits.
Live example.
The overhead includes:
Some calling conventions make passing a struct wrapping only an int be passed differently than an int.
On destruction, we check every one of these to see if it is 0 to decide if we want to call glDeleteShader; compilers can sometimes prove that something is guaranteed zero and skip that check. But it won't tell you if it did manage to pull that off. (OTOH, humans are notoriously bad at proving that they kept track of all resources, so a few runtime checks aren't the worst thing).
If you are doing a completely unoptimized build, there are going to be a few extra instructions when you call a OpenGL function. But after any non-zero level of inlineing by the compiler they will disappear.
The type isn't "trivial" (a term in the C++ standard) in a few ways (copyable, destroyable, constructible), which makes doing things like memset illegal under the C++ standard; you can't treat it like raw memory in a few low level ways.
A problem!
Many OpenGL implementations have pointers for glDeleteShader/glCreateShader etc, and the above relies on them being actual functions not pointers or macros or whatever.
There are two easy workarounds. The first is to add a & to the deleter arguments above (two spots). This has the problem that it only works when they are actually pointers now, and not when they are actual functions.
Making code that works in both cases is a bit tricky, but I think almost every GL implementation uses function pointers, so you should be good unless you want to make a "library quality" implementation. In that case, you can write some helper types that create constexpr function pointers that call the function pointer (or not) by name.
Finally, apparently some destructors require extra parameters. Here is a sketch.
using GLuint=std::uint32_t;
GLuint glCreateShaderImpl() { return 7; }
auto glCreateShader = glCreateShaderImpl;
void glDeleteShaderImpl(GLuint x) { std::cout << x << " deleted\n"; }
auto glDeleteShader = glDeleteShaderImpl;
std::pair<GLuint, GLuint> glCreateTextureWrapper() { return {7,1024}; }
void glDeleteTextureImpl(GLuint x, GLuint size) { std::cout << x << " deleted size [" << size << "]\n"; }
auto glDeleteTexture = glDeleteTextureImpl;
template<class Int>
struct nullable{
Int val=0;
nullable()=default;
nullable(Int v):val(v){}
nullable(std::nullptr_t){}
friend bool operator==(std::nullptr_t, nullable const& self){return !static_cast<bool>(self);}
friend bool operator!=(std::nullptr_t, nullable const& self){return static_cast<bool>(self);}
friend bool operator==(nullable const& self, std::nullptr_t){return !static_cast<bool>(self);}
friend bool operator!=(nullable const& self, std::nullptr_t){return static_cast<bool>(self);}
operator Int()const{return val;}
};
template<class Int, auto& deleter>
struct IntDeleter;
template<class Int, class...Args, void(*&deleter)(Int, Args...)>
struct IntDeleter<Int, deleter>:
std::tuple<std::decay_t<Args>...>
{
using base = std::tuple<std::decay_t<Args>...>;
using base::base;
using pointer=nullable<Int>;
void operator()(pointer p)const{
std::apply([&p](std::decay_t<Args> const&...args)->void{
deleter(p, args...);
}, static_cast<base const&>(*this));
}
};
template<class Int, void(*&deleter)(Int)>
using IntResource=std::unique_ptr<Int, IntDeleter<Int,deleter>>;
using GLShaderResource=IntResource<GLuint,glDeleteShader>;
using GLTextureResource=std::unique_ptr<GLuint,IntDeleter<GLuint, glDeleteTexture>>;
int main() {
auto res = GLShaderResource(glCreateShader());
std::cout << res.get() << "\n";
auto tex = std::make_from_tuple<GLTextureResource>(glCreateTextureWrapper());
std::cout << tex.get() << "\n";
}
Implement a deleter yourself, and let the deleter be a friend of your class.
Then edit your declaration like this:
static std::unique_ptr<GLSLShader, your_deleter> create();
I've been programming C++ for a while now and I'm starting to doubt that the rule use references whenever possible should be applied everywhere.
Unlike this related SO post I'm interested in a different kind of thing.
In my experience the reference/pointer mix messes up your code:
std::vector<Foo *> &x = get_from_somewhere(); // OK? reference as return value
some_func_pass_by_ref(x); // OK reference argument and reference variable
some_func_by_pointer(x[4]); // OK pointer arg, pointer value
some_func_pass_elem_by_ref(*x[5]); // BAD: pointer value, reference argument
some_func_that_requires_vec_ptr(&x); // BAD: reference value, pointer argument
One option would be to replace & with * const like Foo & with Foo * const
void some_func_by_ref(const std::vector<Foo * const> * const); // BAD: verbose!
this way at least the traversals are gone. and me rewriting function headers is gone, because all arguments will be pointers... at the price of polluting the code with const instead of pointer arithmetic (mainly & and *).
I would like to know how and when you apply use references whenever possible rule.
considering:
minimal rewriting of function prototypes (i.e.: oh damn I need need to rewrite alot of prototypes because I want to put this referenced element into a container)
increasing readability
avoid application of * to transform Foo* to Foo& and vice versa
avoid excessive const usage as in * const
NOTES: one thing I figured is to use pointers whenever I intend to ever put the element into an STL container (see boost::ref)
I don't think this is something C++03 specific but C++11 solutions are fine if they can be backported to C++03 (i.e.: NRVO instead of move-semantics).
When should I use references in C++?
When you need to treat a variable like the object itself (most cases when you don't explicitly need pointers and don't want to take ownership of an object).
I would like to know how and when you apply use references whenever possible rule.
whenever possible, except when you need to:
work on the address (log the address, diagnose or write custom memory allocation, etc)
take ownership of parameter (pass by value)
respect an interface that requires a pointer (C interoperability code and legacy code).
Bjarne Stroustrup stated in his book that he introduced references to the language because operators needed to be called without making a copy of the object (that would mean "by pointer") and he needed to respect syntax similar to calling by value (that would mean "not by pointer") (and thus references were born).
In short, you should use pointers as little as possible:
if the value is optional ("can be null") then use a std::optional around it, not a pointer
if you need to take ownership of the value, receive parameter by value (not a pointer)
if you need to read a value without modifying it, receive parameter by const &
if you need to allocate dynamically or return newly/dynamically allocated object, transmit value by one of: std::shared_ptr, std::unique_ptr, your_raii_pointer_class_here - not by (raw) pointer
if you need to pass a pointer to C code, you should still use the std::xxx_ptr classes, and get the pointer using .get() for getting the raw pointer.
one thing I figured is to use pointers whenever I intend to ever put the element into an STL container (or can I get rid of this?)
You can use Boost Pointer Container library.
IMHO the rule stands because raw pointers are dangerous because ownership and destruction responsibility becomes rapidly unclear. Hence the multiple encapsulations around the concept (smart_ptr, auto_ptr, unique_ptr, ...).
First, consider using such encapsulations instead of raw pointer in your container.
Second, why do you need to put pointers in a container ? I mean, they're meant to contain full objects ; they have an allocator as template argument for precise memory allocation after all. Most of the time, you want pointers because you have an OO-approach making heavy use of polymorphism. You should reconsider this approach. For example you can replace:
struct Animal {virtual std::string operator()() = 0;};
struct Dog : Animal {std::string operator()() {return "woof";}};
struct Cat : Animal {std::string operator()() {return "miaow";}};
// can not have a vector<Animal>
By something like this, using Boost.Variant :
struct Dog {std::string operator()() {return "woof";}};
struct Cat {std::string operator()() {return "miaow";}};
typedef boost::variant<Dog, Cat> Animal;
// can have a vector<Animal>
This way when you add a new animal, you inherit nothing, you just add it to the variant.
You can also consider, a little bit more complicated, but far more generic, using Boost.Fusion :
struct Dog {std::string talk; Dog() : talk("wook"){}};
struct Cat {std::string talk; Cat() : talk("miaow"){}};
BOOST_FUSION_ADAPT_STRUCT(Dog, (std::string, talk))
BOOST_FUSION_ADAPT_STRUCT(Cat, (std::string, talk))
typedef boost::fusion::vector<std::string> Animal;
int main()
{
vector<Animal> animals;
animals.push_back(Dog());
animals.push_back(Cat());
using boost::fusion::at;
using boost::mpl::int_;
for(auto a : animals)
{
cout << at<int_<0>>(a) << endl;
}
}
This way you do not even modify an aggregate like variant nor the algorithms on animals, you just need to provide a FUSION_ADAPT matching the used algorithms prerequisites. Both versions (variant and fusion) let you define orthogonal object groups, a useful thing you can not do with inheritance trees.
The following ways seem reasonable dealing with this:
boost and C++11 have a class that can cheaply be used to store references in a container: Reference Wrapper
A good advice is to use the handle/body idiom more often instead of passing around raw pointers. This also solves the ownership issue of the memory that is governed by the reference or the pointer. Sean Parent from Adobe has pointed this out at a talk at going native 2013.
I chose to use the Handle/Body Idiom approach because it gives pointers automatically copy/assign behaviour while hiding the underlying implementation and ownership semantics. It also acts as kind of a compile time firewall reducing header file inclusion.
I'm using an old open-source library, with the following (simplified) API of interest:
// some class that holds a raw pointer to memory on the heap
// DOES NOT delete it in its destructor
// DOES NOT do a "deep" copy when copied/assigned (i.e., after copying both objects
// will point to the same address)
class Point;
// function used to construct a point and allocate its data on the heap
Point AllocPoint();
// function used to release the memory of the point's data
void DeallocPoint(Point& p);
// Receives a pointer/c-array of Points, along with the number of points
// Doesn't own the memory
void Foo(Point* points, int npts);
What's the best (safest/most readable/most elegant) way of using this API in C++11. I can't simply use vector<unique_ptr<Point, PointDeleter>> (where PointDeleter is a simple custom deleter I can implement), because then I will not be able to use the function Foo (which expects Point* and not unique_ptr<Point>*).
Thanks
If you really want to make it look nice, you're probably going to have to write a set of really comprehensive wrappers which completely hide the library's API - effectively, wrap the entire library with one that behaves in a modern C++ way on the outside and hides all the mess inside.
Not a pleasant task, but if you can get the behaviour of that library right then it should make your life a lot easier in the long term. Might not be worth it if you're not going to use this external library very extensively though.
I would wrap this non-RAII C-like API in RAII building blocks, and then use them in C++11 code.
For example: you can define a RaiiPoint class that wraps the (non-RAII) Point class, and in its constructor calls AllocPoint(), in the destructor DeallocPoint(). Then you can define proper copy constructor and copy operator=, or just implement move semantics (with move constructor and move operator=), or make the wrapper class both copyable and movable, basing on your requirements.
Then you can simply use a std::vector<RaiiPoint> with your RAII-based wrapper class.
(This is a general approach that you can use when you want to use C libraries in modern C++ code: you can wrap the "raw" C library handles and objects in safe RAII boundaries, and use these robust safe wrapper classes in your modern C++ code.)
You can use std::vector<Point>, calling Foo( &v[0],
v.size() ). But managing the memory here could be tricky,
since Point apparently doesn't provide any clean copy and
assignment; a custom deleter in the allocator will be called for
each element, even if it is copied.
If the vector should actually own the points, then you can wrap
it in a more complex class, which calls AllocPoint for each
insertion (and inserts the results), and DeallocPoint for each
removal (and for everything remaining in the vector on
destruction). This class should not allow write access to the
Point (non-const operator[], non-const iterators, etc.),
however, since this would allow changing any pointers in
Point, and loosing what is needed for DeallocPoint to work
correctly. Presumably, there other functions for manipulating
Point; you'll have to arrange for these to be available
through the wrapper interface.
"You" could write a simple wrapper to free the memory:
struct PointVectorWrapper {
vector<Point> points;
~PointVectorWrapper() {
for (Point& p : points) {
DeallocPoint(p);
}
}
PointVectorWrapper& operator=(const PointVectorWrapper&) = delete;
PointVectorWrapper(const PointVectorWrapper&) = delete;
};
// Now the usage is simple and safe:
PointVectorWrapper points;
// ... populate points ...
Foo(points.data(), points.size())
But this seems a little "adhoc". What's a more standard/reusable solution?
You could use a standard vector with a custom allocator, that invoke AllocPoint on construct method and DeallocPoint() on destruct method.
template<typename T>
class CustomAllocator : public std::allocator<T>
{
//Rebind and constructors
};
template<>
class CustomAllocator<Point> : public std::allocator<Point>
{
//Rebind and constructors
//For c++11
void construct( pointer p )
{
new (p) Point();
*p = AllocPoint();
}
void construct( pointer p, const_reference val )
{
construct(p);
//copy member from val to point if neccessary
};
void destroy( pointer p )
{
DeallocPoint(*p);
p->~Point();
}
};
typedef std::vector<Point, CustomAllocator<Point> > PointVector;
I'm not a very experienced c++ coder and this has me stumped. I am passing a object (created elsewhere) to a function, I want to be able to store that object in some array and then run through the array to call a function on that object. Here is some pseudo code:
void AddObject(T& object) {
object.action(); // this works
T* objectList = NULL;
// T gets allocated (not shown here) ...
T[0] = object;
T[0].action(); // this doesn't work
}
I know the object is passing correctly, because the first call to object.action() does what it should. But when I store object in the array, then try to invoke action() it causes a big crash.
Likely my problem is that I simply tinkered with the .'s and *'s until it compiled, T[0].action() compliles but crashes at runtime.
The simplest answer to your question is that you must declare your container correctly and you must define an appropriate assigment operator for your class. Working as closely as possible from your example:
typedef class MyActionableClass T;
T* getGlobalPointer();
void AddInstance(T const& objInstance)
{
T* arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **objects**
//whose first element we don't mind losing
//**copy** the instance we've received
arrayFromElsewhere[0] = objInstance;
//now invoke the action() method on our **copy**
arrayFromElsewhere[0].action();
}
Note the signature change to const reference which emphasizes that we are going to copy the original object and not change it in any way.
Also note carefully that arrayFromElsewhere[0].action() is NOT the same as objInstance.action() because you have made a copy — action() is being invoked in a different context, no matter how similar.
While it is obvious you have condensed, the condensation makes the reason for doing this much less obvious — specifying, for instance, that you want to maintain an array of callback objects would make a better case for “needing” this capability. It is also a poor choice to use “T” like you did because this tends to imply template usage to most experienced C++ programmers.
The thing that is most likely causing your “unexplained” crash is that assignment operator; if you don't define one the compiler will automatically generate one that works as a bitwise copy — almost certainly not what you want if your class is anything other than a collection of simple data types (POD).
For this to work properly on a class of any complexity you will likely need to define a deep copy or use reference counting; in C++ it is almost always a poor choice to let the compiler create any of ctor, dtor, or assignment for you.
And, of course, it would be a good idea to use standard containers rather than the simple array mechanism you implied by your example. In that case you should probably also define a default ctor, a virtual dtor, and a copy ctor because of the assumptions made by containers and algorithms.
If, in fact, you do not want to create a copy of your object but want, instead, to invoke action() on the original object but from within an array, then you will need an array of pointers instead. Again working closely to your original example:
typedef class MyActionableClass T;
T** getGlobalPointer();
void AddInstance(T& objInstance)
{
T** arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **pointers**
//whose first element we don't mind losing
//**reference** the instance we've received by saving its address
arrayFromElsewhere[0] = &objInstance;
//now invoke the action() method on **the original instance**
arrayFromElsewhere[0]->action();
}
Note closely that arrayFromElsewhere is now an array of pointers to objects instead of an array of actual objects.
Note that I dropped the const modifier in this case because I don’t know if action() is a const method — with a name like that I am assuming not…
Note carefully the ampersand (address-of) operator being used in the assignment.
Note also the new syntax for invoking the action() method by using the pointer-to operator.
Finally be advised that using standard containers of pointers is fraught with memory-leak peril, but typically not nearly as dangerous as using naked arrays :-/
I'm surprised it compiles. You declare an array, objectList of 8 pointers to T. Then you assign T[0] = object;. That's not what you want, what you want is one of
T objectList[8];
objectList[0] = object;
objectList[0].action();
or
T *objectList[8];
objectList[0] = &object;
objectList[0]->action();
Now I'm waiting for a C++ expert to explain why your code compiled, I'm really curious.
You can put the object either into a dynamic or a static array:
#include <vector> // dynamic
#include <array> // static
void AddObject(T const & t)
{
std::array<T, 12> arr;
std::vector<T> v;
arr[0] = t;
v.push_back(t);
arr[0].action();
v[0].action();
}
This doesn't really make a lot of sense, though; you would usually have defined your array somewhere else, outside the function.
I'm trying to learn C++, and trying to understand returning objects. I seem to see 2 ways of doing this, and need to understand what is the best practice.
Option 1:
QList<Weight *> ret;
Weight *weight = new Weight(cname, "Weight");
ret.append(weight);
ret.append(c);
return &ret;
Option 2:
QList<Weight *> *ret = new QList();
Weight *weight = new Weight(cname, "Weight");
ret->append(weight);
ret->append(c);
return ret;
(of course, I may not understand this yet either).
Which way is considered best-practice, and should be followed?
Option 1 is defective. When you declare an object
QList<Weight *> ret;
it only lives in the local scope. It is destroyed when the function exits. However, you can make this work with
return ret; // no "&"
Now, although ret is destroyed, a copy is made first and passed back to the caller.
This is the generally preferred methodology. In fact, the copy-and-destroy operation (which accomplishes nothing, really) is usually elided, or optimized out and you get a fast, elegant program.
Option 2 works, but then you have a pointer to the heap. One way of looking at C++ is that the purpose of the language is to avoid manual memory management such as that. Sometimes you do want to manage objects on the heap, but option 1 still allows that:
QList<Weight *> *myList = new QList<Weight *>( getWeights() );
where getWeights is your example function. (In this case, you may have to define a copy constructor QList::QList( QList const & ), but like the previous example, it will probably not get called.)
Likewise, you probably should avoid having a list of pointers. The list should store the objects directly. Try using std::list… practice with the language features is more important than practice implementing data structures.
Use the option #1 with a slight change; instead of returning a reference to the locally created object, return its copy.
i.e. return ret;
Most C++ compilers perform Return value optimization (RVO) to optimize away the temporary object created to hold a function's return value.
In general, you should never return a reference or a pointer. Instead, return a copy of the object or return a smart pointer class which owns the object. In general, use static storage allocation unless the size varies at runtime or the lifetime of the object requires that it be allocated using dynamic storage allocation.
As has been pointed out, your example of returning by reference returns a reference to an object that no longer exists (since it has gone out of scope) and hence are invoking undefined behavior. This is the reason you should never return a reference. You should never return a raw pointer, because ownership is unclear.
It should also be noted that returning by value is incredibly cheap due to return-value optimization (RVO), and will soon be even cheaper due to the introduction of rvalue references.
passing & returning references invites responsibilty.! u need to take care that when you modify some values there are no side effects. same in the case of pointers. I reccomend you to retun objects. (BUT IT VERY-MUCH DEPENDS ON WHAT EXACTLY YOU WANT TO DO)
In ur Option 1, you return the address and Thats VERY bad as this could lead to undefined behaviour. (ret will be deallocated, but y'll access ret's address in the called function)
so use return ret;
It's generally bad practice to allocate memory that has to be freed elsewhere. That's one of the reasons we have C++ rather than just C. (But savvy programmers were writing object-oriented code in C long before the Age of Stroustrup.) Well-constructed objects have quick copy and assignment operators (sometimes using reference-counting), and they automatically free up the memory that they "own" when they are freed and their DTOR automatically is called. So you can toss them around cheerfully, rather than using pointers to them.
Therefore, depending on what you want to do, the best practice is very likely "none of the above." Whenever you are tempted to use "new" anywhere other than in a CTOR, think about it. Probably you don't want to use "new" at all. If you do, the resulting pointer should probably be wrapped in some kind of smart pointer. You can go for weeks and months without ever calling "new", because the "new" and "delete" are taken care of in standard classes or class templates like std::list and std::vector.
One exception is when you are using an old fashion library like OpenCV that sometimes requires that you create a new object, and hand off a pointer to it to the system, which takes ownership.
If QList and Weight are properly written to clean up after themselves in their DTORS, what you want is,
QList<Weight> ret();
Weight weight(cname, "Weight");
ret.append(weight);
ret.append(c);
return ret;
As already mentioned, it's better to avoid allocating memory which must be deallocated elsewhere. This is what I prefer doing (...these days):
void someFunc(QList<Weight *>& list){
// ... other code
Weight *weight = new Weight(cname, "Weight");
list.append(weight);
list.append(c);
}
// ... later ...
QList<Weight *> list;
someFunc(list)
Even better -- avoid new completely and using std::vector:
void someFunc(std::vector<Weight>& list){
// ... other code
Weight weight(cname, "Weight");
list.push_back(weight);
list.push_back(c);
}
// ... later ...
std::vector<Weight> list;
someFunc(list);
You can always use a bool or enum if you want to return a status flag.
Based on experience, do not use plain pointers because you can easily forget to add proper destruction mechanisms.
If you want to avoid copying, you can go for implementing the Weight class with copy constructor and copy operator disabled:
class Weight {
protected:
std::string name;
std::string desc;
public:
Weight (std::string n, std::string d)
: name(n), desc(d) {
std::cout << "W c-tor\n";
}
~Weight (void) {
std::cout << "W d-tor\n";
}
// disable them to prevent copying
// and generate error when compiling
Weight(const Weight&);
void operator=(const Weight&);
};
Then, for the class implementing the container, use shared_ptr or unique_ptr to implement the data member:
template <typename T>
class QList {
protected:
std::vector<std::shared_ptr<T>> v;
public:
QList (void) {
std::cout << "Q c-tor\n";
}
~QList (void) {
std::cout << "Q d-tor\n";
}
// disable them to prevent copying
QList(const QList&);
void operator=(const QList&);
void append(T& t) {
v.push_back(std::shared_ptr<T>(&t));
}
};
Your function for adding an element would make use or Return Value Optimization and would not call the copy constructor (which is not defined):
QList<Weight> create (void) {
QList<Weight> ret;
Weight& weight = *(new Weight("cname", "Weight"));
ret.append(weight);
return ret;
}
On adding an element, the let the container take the ownership of the object, so do not deallocate it:
QList<Weight> ql = create();
ql.append(*(new Weight("aname", "Height")));
// this generates segmentation fault because
// the object would be deallocated twice
Weight w("aname", "Height");
ql.append(w);
Or, better, force the user to pass your QList implementation only smart pointers:
void append(std::shared_ptr<T> t) {
v.push_back(t);
}
And outside class QList you'll use it like:
Weight * pw = new Weight("aname", "Height");
ql.append(std::shared_ptr<Weight>(pw));
Using shared_ptr you could also 'take' objects from collection, make copies, remove from collection but use locally - behind the scenes it would be only the same only object.
All of these are valid answers, avoid Pointers, use copy constructors, etc. Unless you need to create a program that needs good performance, in my experience most of the performance related problems are with the copy constructors, and the overhead caused by them. (And smart pointers are not any better on this field, I'd to remove all my boost code and do the manual delete because it was taking too much milliseconds to do its job).
If you're creating a "simple" program (although "simple" means you should go with java or C#) then use copy constructors, avoid pointers and use smart pointers to deallocate the used memory, if you're creating a complex programs or you need a good performance, use pointers all over the place, and avoid copy constructors (if possible), just create your set of rules to delete pointers and use valgrind to detect memory leaks,
Maybe I will get some negative points, but I think you'll need to get the full picture to take your design choices.
I think that saying "if you're returning pointers your design is wrong" is little misleading. The output parameters tends to be confusing because it's not a natural choice for "returning" results.
I know this question is old, but I don't see any other argument pointing out the performance overhead of that design choices.