I came accross several questions where answers state that using T* is never the best idea.
While I already make much use of RIIC, there is one particular point in my code, where I use T*. Reading about several auto-pointers, I couldn't find one where I'd say that I have a clear advantage from using it.
My scenario:
class MyClass
{
...
// This map is huge and only used by MyClass and
// and several objects that are only used by MyClass as well.
HashMap<string, Id> _hugeIdMap;
...
void doSomething()
{
MyMapper mapper;
// Here is what I pass. The reason I can't pass a const-ref is
// that the mapper may possibly assign new IDs for keys not yet in the map.
mapper.setIdMap(&_hugeIdMap);
mapper.map(...);
}
}
MyMapper
now has a HashMap<...>*
member, which - according to highly voted answers in questions on unrelated problems - never is a good idea (Altough the mapper will go out of scope before the instance of MyClass
does and hence I do not consider it too much of a problem. There's no new
in the mapper and no delete
will be needed).
So what is the best alternative in this particular use-case?
Use shared_ptr if you want to share ownership of a resource. Many shared_ptr can point to a single resource. shared_ptr maintains reference count for this propose. when all shared_ptr's pointing to resource goes out of scope the resource is destroyed.
As for other differences, unique_ptr can handle arrays correctly (it will call delete[] , while auto_ptr will attempt to call delete .
Smart pointers try to prevent memory leaks by making the resource deallocation automatic: when the pointer to an object (or the last in a series of pointers) is destroyed, for example because it goes out of scope, the pointed object is destroyed too.
Personally I think a raw pointer (or reference) is okay here. Smart pointers are concerned with managing the lifetime of the object pointed to, and in this case MyMapper
isn't managing the lifetime of that object, MyClass
is. You also shouldn't have a smart pointer pointing to an object that was not dynamically allocated (which the hash map isn't in this case).
Personally, I'd use something like the following:
class MyMapper
{
public:
MyMapper(HashMap<string, Id> &map)
: _map(map)
{
}
private:
HashMap<string, Id> &_map
};
Note that this will prevent MyMapper
from having an assignment operator, and it can only work if it's acceptable to pass the HashMap in the constructor; if that is a problem, I'd make the member a pointer (though I'd still pass the argument as a reference, and do _map(&map)
in the initializer list).
If it's possible for MyMapper
or any other class using the hash map to outlive MyClass
, then you'd have to start thinking about smart pointers. In that case, I would probably recommend std::shared_ptr
, but you'd have to use it everywhere: _hugeIdMap
would have to be a shared_ptr
to a dynamically allocated value, not a regular non-pointer field.
Update:
Since you said that using a reference is not acceptable due to the project's coding standards, I would suggest just sticking with a raw pointer for the reasons mentioned above.
Naked pointers (normally referred to as raw pointers) are just fine when the object has no responsibility to delete the object. In the case of MyMapper then the pointer points to an object already owned by MyClass and is therefore absolutely fine to not delete it. The problem arises when you use raw pointers when you do intend for objects to be deleted through them, which is where problems lie. People only ask questions when they have problems, which is why you almost always see it only used in a problematic context, but raw pointers in a non-owning context is fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With