One of the thing that has been confusing for me while learning C++ (and Direct3D, but that some time ago) is when you should use a pointer member in a class. For example, I can use a non-pointer declaration:
private:
SomeClass instance_;
Or I could use a pointer declaration
private:
Someclass * instance_
And then use new() on it in the constructor.
I understand that if SomeClass could be derived from another class, a COM object or is an ABC then it should be a pointer. Are there any other guidelines that I should be aware of?
A pointer has following advantages:
a) You can do a lazy initialization, that means to init / create the object only short before the first real usage.
b) The design: if you use pointers for members of an external class type, you can place a forward declaration above your class and thus don't need to include the headers of that types in your header - instead of that you include the third party headers in your .cpp - that has the advantage to reduce the compile time and prevents side effects by including too many other headers.
class ExtCamera; // forward declaration to external class type in "ExtCamera.h"
class MyCamera {
public:
MyCamera() : m_pCamera(0) { }
void init(const ExtCamera &cam);
private:
ExtCamera *m_pCamera; // do not use it in inline code inside header!
};
c) A pointer can be deleted anytime - so you have more control about the livetime and can re-create an object - for example in case of a failure.
The advantages of using a pointer are outlined by 3DH: lazy initialization, reduction in header dependencies, and control over the lifetime of the object.
The are also disadvantages. When you have a pointer data member, you probably have to write your own copy constructor and assignment operator, to make sure that a copy of the object is created properly. Of course, you also must remember to delete the object in the destructor. Also, if you add a pointer data member to an existing class, you must remember to update the copy constructor and operator=. In short, having a pointer data member is more work for you.
Another disadvantage is really the flip side of the control over the lifetime of the object pointed to by the pointer. Non-pointer data members are destroyed automagically when the object is destroyed, meaning that you can always be sure that they exist as long as the object exists. With the pointer, you have to check for it being nullptr, meaning also that you have to make sure to set it to nullptr whenever it doesn't point to anything. Having to deal with all this may easily lead to bugs.
Finally, accessing non-pointer members is likely to be faster, because they are contiguous in memory. On the other hand, accessing pointer data member pointing to an object allocated on the heap is likely to cause a cache miss, making it slower.
There is no single answer to your question. You have to look at your design, and decide whether the advantages of pointer data members outweigh the additional headache. If reducing compile time and header dependencies is important, use the pimpl idiom. If your data member may not be necessary for your object in certain cases, use a pointer, and allocate it when needed. If these do not sound like compelling reasons, and you do not want to do extra work, then do not use a pointer.
If lazy initialization and the reduction of header dependencies are important, then you should first consider using a smart pointer, like std::unique_ptr or std::shared_ptr, instead of a raw pointer. Smart pointers save you from many of the headaches of using raw pointers described above.
Of course, there are still caveats. std::unique_ptr cleans up after itself, so you do not need to add or modify the destructor of your class. However, it is non-copiable, so having a unique pointer as a data member makes your class non-copiable as well.
With std::shared_ptr, you do not have to worry about the destructor or copying or assignment. However, the shared pointer incurs a performance penalty for reference counting.
Allocate it on the stack if you can, from the free-store if you have to. There is a similar question here, where you will find all the "why's".
The reason you see lots of pointer usage when it comes to games and stuff is because DirectX is a COM interface, and in honesty, most games programmers from back in the day aren't really C++ programmers, they are C-with-classes programmers, and in C pointer usage is very common.
Another reason to use pointers would be dynamic binding. If you have a base class with a virtual method and some derived classes, you can only get dynamic binding using pointers.
Related
What are the differences between declaring a variable in a header file as pointer or non-pointer? I am not sure if I understand the differences correctly.
E.g.
class MyClass {
private:
MyOtherClass* moc; // pointer
MyOtherClass moc2; // no pointer
}
So far I have come up with the following advantages/disadvantages when declaring a variable as pointer.
Advantages:
Lazy instantiation (no immediate creation of the object)
Variable lives on the heap which is much larger than the stack
Not only the default constructor can be used
Disadvantages:
Must be deleted manually in the destructor (btw. when is such a non-pointer variable destructed? When the program ends?)
What else is there to say?
Having an object signifies ownership. It's composition. Pointers can signify ownership, but most of the time they mean aggregation.
I.e. MyClass has a moc2 and uses moc.
Take your decision thinking about the design of the classes and how they interact with each other, not based on the pointer vs. object debate. Each MyClass object will have its own moc2 member, but multiple MyClass objects can share a moc between them.
Regarding your proposed advantages/disadvantages:
Advantages:
Lazy instantiation (no immediate creation of the object) - the pointer itself is initialized - remember your member is a pointer not an object. But I'll give you that you sometimes need this, although it's most of the time a code-smell.
Variable lives on the heap which is much larger than the stack - not necessarily - you can have a pointer to a stack-based variable as well. Also, if a MyClass object is allocated on the heap, so will moc2.
Not only the default constructor can be used - non-issue, you can use any constructor in both cases (see initialization-lists).
Disadvantages:
Must be deleted manually in the destructor (btw. when is such a non-pointer variable destructed? When the program ends?) - only if MyClass owns the member - it could be a pointer to some object created elsewhere, so MyClass isn't responsible for managing it.
Some of the advantages/disadvantages need correction, so here you go:
Advantages:
- Lazy instantiation (no immediate creation of the object)
- No need for the definition of the class to be visible, forward declaration suffices
Disadvantages:
- Must be deleted manually in the destructor
- You need to manually declare all copy constructors and assignment operators
- more complicated access (-> instead of .)
Some alternatives: smart pointer (std::unique_ptr). Has all advantages of the raw pointer and no need for explicit delete in the destructor, generally is much safer. Raw pointers should never be used unless really necessary, so if you need advantages of the pointer, use smart one.
And if you want lazy initialisation boost::optional may be used.
And in the end comments to your list:
Variable lives on the heap which is much larger than the stack
Not entirely true. If it is a pointer and object is created with new, the object will be in the heap. Otherwise it won't necessarily be on the stack. It will be where the parent object is. If the parent object is on the heap, the enclosed object - begin part of it - is on the heap also.
Not only the default constructor can be used
Not true at all, will initialisation list you can specify any arguments for member constructor.
Having a pointer does not automatically mean that you will have dynamically allocated variables. You can very much have a pointer to automatic or static variables as well (I'm not saying this is common or encouraged, I'm just being technical). Having a pointer gives you the option of allocating variables dynamically, but the downside is you have to manage the memory yourself, (See here and here).
As for when to use either, this has already been discussed on SO here
One difference that comes to mind is in header inclusions. When you have a pointer to an instance as a member, then you are permitted to forward-declare that type, whereas including it by value means that you have to include the header, which slows down build times.
I'm implementing a "variant" class which must have the smallest possible memory footprint and store some objects with a shared pointer mechanism.
For this, I would like to make a union within the class of all variable types. This includes some shared_ptr's.
The operator= and copy constructors must change the data type of the variant, hence switching to another member in the union. Upon switching to a shared_ptr, this one should be reset to null without deleting/deowning the pointer. Is there a way to do this?
Of course, there would be other ways to implement this but they are generally more complex, less safe or more memory consuming in my case. Any suggestion welcome though.
Thanks!
Resetting to null isn't sufficient; the implementations of
std::shared_ptr I know also have a pointer to the reference
count, which must be deleted as well.
You need to keep track of what is currently in the union, and
use explicit calls to the destructor and placement new for
construction any time the type changes (and in the constructors
and the destructor).
I have a problem which I cannot understand:
Let's Say I have a class System with several member fields, and one of them is of type unordered_map, so when I declare the class in the header file, I write at the beginning of the header #include <unordered_map>.
Now, I have two ways of declaring this field:
1.std::unordered_map<std::string,int> umap;
2.std::unordered_map<std::string,int>* p_umap;
Now in the constructor of the class, if I choose the first option, there is no need to initialize that field in the initializer list since the constructor of class System will call the default constructor for the field umap as part of constructing an instance of type class System.
If I choose the second option, I should initialize the field p_umap in the constructor (in the initialize list) with the operator new and in the destructor, to delete this dynamic allocation.
What is the difference between these two options? If you have a class that one of it's fields is of type unordered_map, how do you declare this field? As a pointer or as a variable of type unordered_map?
In a situation like the one you are describing, it seems like the first option is preferable. Most likely, in fact, the unordered map is intended to be owned by the class it is a data member of. In other words, its lifetime should not be extended beyond the lifetime of the encapsulating class, and the encapsulating class has the responsibility of creating and destroying the unordered map.
While with option 1 all this work is done automatically, with option 2 you would have to take care of it manually (and take care of correct copy-construction, copy-assignment, exception-safety, lack of memory leaks, and so on). Surely you could use smart pointers (e.g. std::unique_ptr<>) to encapsulate this responsibility into a wrapper that would take care of deleting the wrapped object when the smart pointer itself goes out of scope (this idiom is called RAII, which is an acronym for Resource Acquisition Is Initialization).
However, it seems to me like you do not really need a pointer at all here. You have an object whose lifetime is completely bounded by the lifetime of the class that contains it. In these situations, you should just not use pointers and prefer declaring the variable as:
std::unordered_map<std::string, int> umap;
Make it not a pointer until you need to make it a pointer.
Pointers are rife with user error.
For example, you forgot to mention that your class System would also need to implement
System( const Sysytem& )
and
System& operator= ( const System& )
or Bad Behavior will arise when you try to copy your object.
The difference is in how you want to be able to access umap. Pointers can allow for a bit more flexibility, but they obviously add complexity in terms of allocation (stack vs heap, destructors and such). If you use a pointer to umap, you can do some pretty convoluted stuff such as making two System's with the same umap. In the end though, go with KISS unless there's a compelling reason not to.
There is no need to define it as pointer. If you do it, you must also make sure to implement copy constructor and assignment operator, or disable them completely.
If there is no specific reason to make it a pointer (and you don't show any) just make it a normal member variable.
I understand that placement new calls are usually matched with explicit calls to the destructor. My question is: if I have no need for a destructor (no code to put there, and no member variables that have destructors) can I safely skip the explicit destructor call?
Here is my use case: I want to write C++ bindings for a C API. In the C API many objects are accessible only by pointer. Instead of creating a wrapper object that contains a single pointer (which is wasteful and semantically confusing). I want
to use placement new to construct an object at the address of the C object. The C++ object will do nothing in its constructor or destructor, and its methods will do nothing but delegate to the C methods. The C++ object will contain no virtual methods.
I have two parts to this question.
Is there any reason why this idea will not work in practice on any production compiler?
Does this technically violate the C++ language spec?
If I understand your question correctly you have a C object in memory and you want to initialize a C++ object with the same layout "over the top" of the existing object.
CppObject* cppobject = new (cobject) CppObject;
While there is no problem with not calling a destructor for the old object - whether this causes resource leaks or other issues is entirely down to the type of the old object and is a user code issue, not a language conformance issue - the fact that you reuse the memory for a new object means that the old object is no longer accessible.
Although the placement form of operator new must just return the address that it was given, there is nothing to stop the new expression itself wiping the memory for the new object before any constructor (if any) is called. Members of the new object that are not initialized according to C++ language rules have unspecified contents which definitely does not mean the same as having the contents of any old object that once lived in the memory being reused.
If I understand you correctly, what you are trying to do is not guaranteed to work.
I think the answer is that if your class is POD (which it is, if it's true that it does nothing in the con/destructor, has no virtual member functions, and has no non-static data members with any of those things), then you don't need to call a constructor or a destructor, its lifetime is just the lifetime of the underlying memory. You can use it the same way that a struct is used in C, and you can call its member functions regardless of whether it has been constructed.
The purpose of placement new is to allow you to create object pools or align multiple objects together in contiguous memory space as with std::vector.
If the objects are C-structs then you do not need placement new to do this, you can simply use the C method of allocating the memory based on sizeof(struct Foo) where Foo is the struct name, and if you allocate multiple objects you may need to multiple the size up to a boundary for alignment.
However there is no need to placement-new the objects there, you can simply memcpy them in.
To answer your main question, yes you still need to call the destructor because other stuff has to happen.
Is there any reason why this idea will not work in practice on any production compiler?
You had damn well be sure your C++ object fits within the size of the C object.
Does this technically violate the C++ language spec?
No, but not everything that is to spec will work like you want.
I understand that placement new calls are usually matched with explicit calls to the destructor. If I have no need for a destructor (no code to put there, and no member variables that have destructors) can I safely skip the explicit destructor call?
Yes. If I don't need to fly to New York before posting this answer, can I safely skip the trip? :) However, if the destructor is truly unneeded because it does nothing, then what harm is there in calling it?
If the compiler can figure out a destructor should be a no-op, I'd expect it to eliminate that call. If you don't write an explicit dtor, remember that your class still has a dtor, and the interesting case – here – is whether it is what the language calls trivial.
Solution: destroy previously constructed objects before constructing over them, even when you believe the dtor is a no-op.
I want to write C++ bindings for a C API. In the C API many objects are accessible only by pointer. Instead of creating a wrapper object that contains a single pointer (which is wasteful and semantically confusing). I want to use placement new to construct an object at the address of the C object.
This is the purpose of layout-compatible classes and reinterpret_cast. Include a static assert (e.g. Boost's macro, 0x static_assert, etc.) checking size and/or alignment, as you wish, for a short sanity check, but ultimately you have to know a bit of how your implementation lays out the classes. Most provide pragmas (or other implementation-specific mechanisms) to control this, if needed.
The easiest way is to contain the C struct within the C++ type:
// in C header
typedef struct {
int n;
//...
} C_A;
C_A* C_get_a();
// your C++
struct A {
void blah(int n) {
_data.num += n;
}
// convenience functions
static A* from(C_A *p) {
return reinterpret_cast<A*>(p);
}
static A const* from(C_A const *p) {
return reinterpret_cast<A const*>(p);
}
private:
C_A _data; // the only data member
};
void example() {
A *p = A::from(C_get_a());
p->blah(42);
}
I like to keep such conversions encapsulated, rather than strewing reinterpret_casts throughout, and more uniform (i.e. compare call-site for const and non-const), hence the convenience functions. It's also a bit harder to modify the class without noticing this type of use must still be supported.
Depending on the exact class, you might make the data member public.
The first question is: why don't you just use a cast? Then there's no issue of the placement new doing anything, and clearly no issue of failing to use a destructor. The result will work if the C and C++ types are layout compatible.
The second question is: what is the point? If you have no virtual functions, you're not using the constructor or destructor, the C++ class doesn't seem to offer any advantages over just using the C type: any methods you write should have been global functions anyhow.
The only advantage I can imagine is if you want to hide the C representation, you can overlay the C object with a class with all private members and use methods for access. Is that your purpose? [That's a reasonable thing to do I think]
This is a simplified example to illustrate the question:
class A {};
class B
{
B(A& a) : a(a) {}
A& a;
};
class C
{
C() : b(a) {}
A a;
B b;
};
So B is responsible for updating a part of C. I ran the code through lint and it whinged about the reference member: lint#1725.
This talks about taking care over default copy and assignments which is fair enough, but default copy and assignment is also bad with pointers, so there's little advantage there.
I always try to use references where I can since naked pointers introduce uncertaintly about who is responsible for deleting that pointer. I prefer to embed objects by value but if I need a pointer, I use auto_ptr in the member data of the class that owns the pointer, and pass the object around as a reference.
I would generally only use a pointer in member data when the pointer could be null or could change. Are there any other reasons to prefer pointers over references for data members?
Is it true to say that an object containing a reference should not be assignable, since a reference should not be changed once initialised?
My own rule of thumb :
Use a reference member when you want the life of your object to be dependent on the life of other objects : it's an explicit way to say that you don't allow the object to be alive without a valid instance of another class - because of no assignment and the obligation to get the references initialization via the constructor. It's a good way to design your class without assuming anything about it's instance being member or not of another class. You only assume that their lives are directly linked to other instances. It allows you to change later how you use your class instance (with new, as a local instance, as a class member, generated by a memory pool in a manager, etc.)
Use pointer in other cases : When you want the member to be changed later, use a pointer or a const pointer to be sure to only read the pointed instance. If that type is supposed to be copyable, you cannot use references anyway. Sometimes you also need to initialize the member after a special function call ( init() for example) and then you simply have no choice but to use a pointer. BUT : use asserts in all your member function to quickly detect wrong pointer state!
In cases where you want the object lifetime to be dependent on an external object's lifetime, and you also need that type to be copyable, then use pointer members but reference argument in constructor That way you are indicating on construction that the lifetime of this object depends on the argument's lifetime BUT the implementation use pointers to still be copyable. As long as these members are only changed by copy, and your type don't have a default constructor, the type should fullfil both goals.
Avoid reference members, because they restrict what the implementation of a class can do (including, as you mention, preventing the implementation of an assignment operator) and provide no benefits to what the class can provide.
Example problems:
you are forced to initialise the reference in each constructor's initialiser list: there's no way to factor out this initialisation into another function (until C++0x, anyway edit: C++ now has delegating constructors)
the reference cannot be rebound or be null. This can be an advantage, but if the code ever needs changing to allow rebinding or for the member to be null, all uses of the member need to change
unlike pointer members, references can't easily be replaced by smart pointers or iterators as refactoring might require
Whenever a reference is used it looks like value type (. operator etc), but behaves like a pointer (can dangle) - so e.g. Google Style Guide discourages it
Objects rarely should allow assign and other stuff like comparison. If you consider some business model with objects like 'Department', 'Employee', 'Director', it is hard to imagine a case when one employee will be assigned to other.
So for business objects it is very good to describe one-to-one and one-to-many relationships as references and not pointers.
And probably it is OK to describe one-or-zero relationship as a pointer.
So no 'we can't assign' then factor.
A lot of programmers just get used with pointers and that's why they will find any argument to avoid use of reference.
Having a pointer as a member will force you or member of your team to check the pointer again and again before use, with "just in case" comment. If a pointer can be zero then pointer probably is used as kind of flag, which is bad, as every object have to play its own role.
Use references when you can, and pointers when you have to.
In a few important cases, assignability is simply not needed. These are often lightweight algorithm wrappers that facilitate calculation without leaving the scope. Such objects are prime candidates for reference members since you can be sure that they always hold a valid reference and never need to be copied.
In such cases, make sure to make the assignment operator (and often also the copy constructor) non-usable (by inheriting from boost::noncopyable or declaring them private).
However, as user pts already commented, the same is not true for most other objects. Here, using reference members can be a huge problem and should generally be avoided.
As everyone seems to be handing out general rules, I'll offer two:
Never, ever use use references as class members. I have never done so in my own code (except to prove to myself that I was right in this rule) and cannot imagine a case where I would do so. The semantics are too confusing, and it's really not what references were designed for.
Always, always, use references when passing parameters to functions, except for the basic types, or when the algorithm requires a copy.
These rules are simple, and have stood me in good stead. I leave making rules on using smart pointers (but please, not auto_ptr) as class members to others.
Yes to: Is it true to say that an object containing a reference should not be assignable, since a reference should not be changed once initialised?
My rules of thumb for data members:
never use a reference, because it prevents assignment
if your class is responsible for deleting, use boost's scoped_ptr (which is safer than an auto_ptr)
otherwise, use a pointer or const pointer
I would generally only use a pointer in member data when the pointer could be null or could change. Are there any other reasons to prefer pointers over references for data members?
Yes. Readability of your code. A pointer makes it more obvious that the member is a reference (ironically :)), and not a contained object, because when you use it you have to de-reference it. I know some people think that is old fashioned, but I still think that it simply prevent confusion and mistakes.
I advise against reference data members becasue you never know who is going to derive from your class and what they might want to do. They might not want to make use of the referenced object, but being a reference you have forced them to provide a valid object.
I've done this to myself enough to stop using reference data members.