Should abstract members of a class be pointers or references? - c++

Should abstract members of a class be pointers or references?
For a toy example, say I have the following class:
class SerializedFileProcessor {
public:
std::string Process(std::string file) const {
std::string text = deserializer.Deserialize(file);
text = processor.Process(text);
return serializer.Serialize(text);
}
private:
IDeserializer? deserializer;
IProcessor? processor;
ISerializer? serializer;
};
Where the (instances of concrete subclasses) deserializer, processor, and serializer are all passed into this class's constructor.
The SerializedFileProcessor doesn't own these and should not delete them.
Should those class members be pointers or references? Or should this pattern be done completely differently?

This is pretty much the hello-world example of dependency injection (/inversion).
There's a similar question here, with different solutions:Dependency injection in C++11 without raw pointers
Edit: I moved my original answer from here into to that question.
Original answer with SerializedFileProcessor example:
The down side of just using a pointer (smart or raw), or even an ordinary C++ reference, is that they allow calling non-const methods from a const context.
I propose a wrapper similar but not identical to std::reference_wrapper (which lacks the const safe accessor). Replace T* with unique_ptr or shared_ptr to get owning versions (also add default move construction).
template<typename T>
struct NonOwningRef{
NonOwningRef() = delete;
NonOwningRef(T& other) noexcept : ptr(std::addressof(other)) { };
NonOwningRef(const NonOwningRef& other) noexcept = default;
const T& value() const noexcept{ return *ptr; };
T& value() noexcept{ return *ptr; };
private:
T* ptr;
};
usage:
class SerializedFileProcessor {
public:
std::string Process(std::string file) const {
std::string text = deserializer.value().Deserialize(file);
text = processor.value().Process(text);
return serializer.value().Serialize(text);
}
private:
NonOwningRef<IDeserializer> deserializer;
NonOwningRef<IProcessor> processor;
NonOwningRef<ISerializer> serializer;
};

They can be either, you must only ensure that the referenced objects do not die before used (i.e. in general its lifetime should exceed the SerializedFileProcessor lifetime).
There is one disadvantage to reference members - it is then virtually impossible to create an assignment operator (so if you need one, then you need a pointer - there are techniques to actually have assignment even for classes with reference members, but they are very nasty). Also in case they are optional, then they need to be pointers (reference is not optional).

If your class doesn't own them, it should not be a reference. Use a pointer and have the owner hold a std::unique_ptr.

Related

Using iterator to retrieve const values pointed to in containers

Const casting container value-types seems not possible. A comment in the other question suggests iterators as a solution, yet does not go into detail.
Since I seemingly cannot simply convert a container from a non-const to a const version as a function parameter, I arrive at Iterators to maybe be able to do the job.
I actually have a vector<shared_ptr<Thing> > to be treated as const vector<shared_ptr<Thing const> >.
With it I intend to use the shared_ptr<Thing const> as further references in other structures, without allowing those structures to alter the Things. Those structures may create their own objects, stored by their own shared_ptr, if they want slightly different content within their containers, while still actively sharing most Things with other objects.
So I would need either shared_ptr<const Thing>&, or const shared_ptr<const Thing>& from an Iterator through the sequence. Either would suffice, but just because one can be indifferent about passing references in this example, because of shared_ptr's copy semantics are about just that.
Yet even just using default const_iterator, retrieved by cbegin(),c.end() and such, will give me a const shared_ptr<Thing>& instead.
Edit: To copy the vector element for element would be one way technically, as in the other question, yet undesired for interface reasons. I am going for reinterpretation here, not copy.
Any suggestions on where a workaround might lie?
Based on your situation, it sounds like defining a custom iterator with the semantics you want is the safe and simple way to go. It's technically correct, hard to accidentally misuse, and fairly fast, just requiring a shared_ptr copy on iterator dereference.
I always recommend boost::iterator_facade or boost::iterator_adaptor for creating an iterator type. Since it will contain the original vector iterator as a "base" implementation, iterator_adaptor is helpful.
class const_Thing_ptr_iterator :
public boost::iterator_adaptor<
const_Thing_ptr_iterator, // CRTP derived type
std::vector<std::shared_ptr<Thing>>::const_iterator, // base iterator type
std::shared_ptr<const Thing>, // value_type
std::random_access_iterator_tag, // traversal type
std::shared_ptr<const Thing> // reference
>
{
public:
const_Thing_ptr_iterator() = default;
explicit const_Thing_ptr_iterator(base_type iter)
: iterator_adaptor(iter) {}
};
The reference iterator type would be std::shared_ptr<const Thing>& by default, but in this case it can't be a reference since there is no object of that type. Normally the class would define some of the behavior functions like dereference or increment, but none are needed here: the only change from the base vector iterator is to the return type of operator*, and the default reference dereference() const { return *base_reference(); } works fine by implicit conversion from const std::shared_ptr<Thing>& to std::shared_ptr<const Thing>.
The class could also be a template taking Thing as its type parameter, to create multiple iterator types.
Then to provide a container-like view object, we can use C++20's std::ranges::subrange to provide begin() and end() and a few other things helping the out the range templates:
#include <ranges>
class const_Thing_ptrs_view
: public std::ranges::subrange<const_Thing_ptr_iterator>
{
public:
explicit const_Thing_ptrs_view(const std::vector<std::shared_ptr<Thing>> &vec)
: subrange(const_Thing_ptr_iterator(vec.begin()),
const_Thing_ptr_iterator(vec.end())) {}
};
Or if that's not available, a simple class with begin() and end():
class const_Thing_ptrs_view {
public:
explicit const_Thing_ptrs_view(const std::vector<std::shared_ptr<Thing>> &vec)
: m_begin(vec.begin()), m_end(vec.end()) {}
const_Thing_ptr_iterator begin() const { return m_begin; }
const_Thing_ptr_iterator end() const { return m_end; }
private:
const_Thing_ptr_iterator m_begin;
const_Thing_ptr_iterator m_end;
};
Demo on godbolt. (Clang doesn't like the ranges code due to this libstdc++ incompatibility; I'm not sure how to get godbolt to switch it to clang's libc++.)
A pretty simple approach might be maintaining a vector of pointers to const already internally – and casting the const away on internal usage.
Warning: Don't consider this as an invitation for doing so carelessly! If you do so, at some point of time you will break something. After all those objects are const for a reason!
In given case, though, this reason is a pure external one – if it wasn't for the public interface the objects wouldn't ever have got const anyway so casting it away again is valid in this very specific case.
class DataOwner
{
public:
std::vector<std::shared_ptr<Thing const>> const& data() const
{
return m_data;
}
void modify()
{
m_data.emplace_back(new Thing());
at(0)->doSomething();
}
// for convenience of the user you might optionally duplicate
// the const interface of `std::vector` here as well
private:
std::vector<std::shared_ptr<Thing const>> m_data;
Thing* at(size_t index)
{
// only one single location where const-casting
// remember: generally a dangerous operation,
// here one of the view valid use cases
return const_cast<Thing*>(m_data[index].get());
// don't forget to document in your own code WHY it is valid here
}
};
Copying around all the shared pointers into new vectors can become pretty expensive quickly, especially if the original source vector gets updated frequently and referring instances thus need to fetch updates again and again.
I personally would thus rather provide either a wrapper around std::vector or around std::shared_ptr that give modifying access only to the data owner (who would be a friend then) while the general interface only allows non-modifying access. Wrapping the vector, though, will require the shared pointers to get copied whenever retrieving one, thus involving reference counting, additionally the solution gets more complex, thus going with the wrapper around the shared pointer here:
struct Thing
{
void doSomething() { }
void doSomethingElse() const { }
};
class DataOwner
{
public:
class SharedPointer
{
public:
SharedPointer(SharedPointer const&) = default;
SharedPointer(SharedPointer&&) = default;
SharedPointer& operator=(SharedPointer const&) = default;
SharedPointer& operator=(SharedPointer&&) = default;
Thing const& operator*() const
{
return *m_data;
}
Thing const* operator->() const
{
return m_data.get();
}
Thing const* get() const
{
return m_data.get();
}
// should be all of the public interface needed...
private:
friend class DataOwner;
SharedPointer(Thing* t) : m_data(t) { }
std::shared_ptr<Thing> m_data;
};
std::vector<SharedPointer> const& data() const
{
return m_data;
}
void modify()
{
m_data.emplace_back(SharedPointer(new Thing()));
m_data[0].m_data->doSomething();
// if needed at many places you might want to have a
// convenience function, see below...
at(0)->doSomething();
}
// for convenience of the user you might optionally duplicate
// the const interface of `std::vector` here as well
private:
std::vector<SharedPointer> m_data;
Thing* at(size_t index)
{
return m_data[index].m_data.get();
}
};
int main()
{
DataOwner o;
o.modify();
o.data()[0]->doSomethingElse();
// o.data()[0]->doSomething(); won't compile!
return 0;
}

lvalue and rvalue getter, is it possible to remove them?

Let's say we have this simple class
struct MyClass {
const std::string &getString() const & {
return m_string;
}
std::string getString() && {
return std::move(m_string);
}
private:
std::string m_string;
};
As we can see, the m_string acts as a non mutable variable in the sense that we cannot modify it.
This structure also preserve the fact that if we move one instance of MyClass to another, the m_string attribute will be moved as well.
Now, we are going to try to refactor the prior structure :
struct MyClass {
std::string m_string;
};
Here, we keeps the fact that we can access it or move it, but we lose the "immutability"... So I tried to write it like that :
struct MyClass {
const std::string m_string;
};
Here we get the immutability thing, however, we lose the potential optimization when we move the object...
So, is it possible to have a behavior similar to the first code, without writing all the getter?
EDIT: the std::string is just for example, but the idea must be usable with all kind of objects
So, is it possible to have a behavior similar to the first code, without writing all the getter?
I can't think of any.
Having said that, the overhead of writing getters and setters for member variables is not such a big burden that I would spend too much time thinking about it.
However, there are some who think that getters and setters of member variables don't add enough protection to a class to even worry about them. If you subscribe to that line of thinking, you can get rid of the getters and setters altogether.
I have used the "no getters and setters" principle for containers of data enough times that I find it natural in many use cases.
You can implement this behavior using a template wrapper type. It seems you want a type that works well with copy and move construction and assignment, but which only provides const access to the wrapped object. All you should need is a wrapper with a forwarding constructor, an implicit conversion operator and dereferencing operators (to force the conversion when implicit conversion doesn't work) :
template<class T>
class immutable
{
public:
template<class ... A>
immutable(A&&... args) : member(std::forward<A>(args)...) {}
public:
operator const T &() const { return member; }
const T & operator*() const { return member; }
const T * operator->() const { return &member; }
private:
T member;
};
This will work well with compiler generated copy and move construction and assignment. The solution is not 100% transparent however. The wrapper will implicitly convert to a reference to the wrapped type, if the context allows it :
#include <string>
struct foo
{
immutable<std::string> s;
};
void test(const std::string &) {}
int main()
{
foo f;
test(f.s); // Converts implicitly
}
But it will need an extra dereference to force the conversion in contexts where implicit conversion will not work :
int main()
{
foo f;
// std::cout << f.s; // Doesn't work
std::cout << *(f.s); // Dereference instead
// f.s.size(); // Doesn't work
f.s->size(); // Dereference instead
}
There was a proposal to add overloading of the . operator, which would allow most cases to work as intended, without a dereferencing. But I'm not sure what the current state of the proposal is.
The solution is to use std::shared_ptr<const std::string>. A shared pointer to a immutable object has value semantic. Copy-on-write can be achieved using shared_ptr::unique(). See Sean Parent presentation 47:46 https://youtu.be/QGcVXgEVMJg.
If only you are willing to declare the copy and defuslt ctor as =default and define the move ctor with const_cast cheat.
MyClass::Myclass()=default;
MyClass::Myclass(Myclass const&)=default;
MyClass::Myclass(Myclass && m)
: m_string{std::move(const_cast<std::string&>(m.m_string))}{};

What should I implement, SetMember(const Member&), SetMember(Member) or SetMember(Member&&)?

Let Memeber be a class and let's assume I have no idea if it supports or need move semantics. For all intents and purposes let's say it isn't even specified/written yet. Which case of the SetMember functions should I implement in an Outer class, which has Member as a member?
If Member would not support move, I would do this:
class Member {
public:
Member(Member&&) = delete;
Member& operator=(Member&&) = delete;
};
class Outer {
Member m_member;
public:
void SetMember(const Member& o) { m_member = o.m_member; } // makes a copy
};
And if Member would support move, I would do this:
class Member {
public:
Member(Member&&);
Member& operator=(Member&&);
};
class Outer {
Member m_member;
public:
void SetMember(Member o) { m_member = std::move(o.m_member); } // makes a copy if needed
};
But since I do not know if it has move or not, do I need to implement both? Like this:
class Outer {
Member m_member;
public:
void SetMember(const Member& o) { m_member = o.m_member; } // makes a copy
void SetMember(Member&& o) { m_member = std::move(o.m_member); } // makes no copy
};
Or should I do this?
class Outer {
Member m_member;
public:
template <class T>
void SetMember(T&& o) { m_member = std::forward<T>(o.m_member); }
};
Why I'm not happy with these two solutions:
In the first solution I see code duplication, which is only needed because I don't know some implementation details of Member namely if it supports move or not.
The second solution leaves me with compilation errors instead of intelli sense errors whenever I try to use SetMember on a wrong type. Also I need a template just because some implementation details of Member.
What's the clean way to handle this situation?
As far as I know passing by value in setters is no longer recommended. At least in case of std::strings when setter is called multiple times, it is highly probable, that the destination variable has enough memory reserved for new value and it's cheaper to just copy the content into already allocated string then create a temporary string and move it.
So no matter if the type is moveable or not it is recommended to pass by const reference and make a copy inside of a setter. If later profiling shows that a temporary is used often as an argument and the cost of copying makes it worth optimizing, an overload for rvalue reference may be added.
See also https://stackoverflow.com/a/26286741/113662

How can I create a Lazy C++ template class that handles types with no default constructor?

Deleting this question in favor the following; an answer to which now handles classes with no default constructor:
How to abstract lazy initialization in C++?
In a nutshell, the code uses placement new/delete. See http://en.wikipedia.org/wiki/Placement_syntax for details...
Just use boost::optional<T> instead of pair of your members m_bInitialized and m_value. Probably you could just use boost::optional<T> instead of your template class Lazy...
If you really want to make it in your own way - then steal some implementation details from boost::optional<T>.
One hint is that this boost class uses placement new:
class Lazy {
public:
bool is_init() const { return m_memberPtr != nullptr; }
T& force()
{
if (!is_init())
m_memberPtr = new (m_memberMemory) T(m_initializer());
return *m_memberPtr;
}
private:
T* m_memberPtr;
alignas(T) char m_memberMemory[sizeof(T)]; // s
};

How to deal with initialization of non-const reference member in const object?

Let's say you have a class
class C
{
int * i;
public:
C(int * v):i(v) {};
void method() const; //this method does not change i
void method(); //this method changes i
}
Now you may want to define const instance of this class
const int * k = whatever;
const C c1(k); //this will fail
but this will fail because of non-const int C's constructor C(int * v)
so you define a const int constructor
C(const int * v):i(v) {}; //this will fail also
But this will fail also since C's member "int * i" is non-const.
What to do in such cases? Use mutable? Casting? Prepare const version of class?
edit: After discussion with Pavel (below) I investigated this problem a bit. To me what C++ does is not correct. Pointer target should be a strict type, that means that you could not for example do the following:
int i;
const int * ptr;
ptr = & i;
In this case language grammar treats const as a promise not to change pointer's target. In addition int * const ptr is a promise not to change pointer value itself. Thus you have two places where const can be applied. Then you may want your class to model a pointer (why not). And here things are falling into pieces. C++ grammar provides const methods which are able to promise not to change field's values itself but there is no grammar to point out that your method will not change targets of your in-class pointers.
A workaround is to define two classes const_C and C for example. It isn't a royal road however. With templates, their partial specializations it's hard not to stuck into a mess. Also all possible arguments variations like const const_C & arg, const C & arg, const_C & arg, C & arg don't look pretty. I really don't know what to do. Use separate classes or const_casts, each way seems to be wrong.
In both cases should I mark methods which don't modify pointer's target as const? Or just follow traditional path that const method doesn't change object's state itself (const method don't care about pointer target). Then in my case all methods would be const, because class is modelling a pointer thus pointer itself is T * const. But clearly some of them modify pointer's target and others do not.
Sounds like you want an object that can wrap either int* (and then behave as non-const), or int const* (and then behave as const). You can't really do it properly with a single class.
In fact, the very notion that const applied to your class should change its semantics like that is wrong - if your class models a pointer or an iterator (if it wraps a pointer, it's likely to be the case), then const applied to it should only mean that it cannot be changed itself, and should not imply anything regarding the value pointed to. You should consider following what STL does for its containers - it's precisely why it has distinct iterator and const_iterator classes, with both being distinct, but the former being implicitly convertible to the latter. As well, in STL, const iterator isn't the same as const_iterator! So just do the same.
[EDIT] Here's a tricky way to maximally reuse code between C and const_C while ensuring const-correctness throughout, and not delving into U.B. (with const_cast):
template<class T, bool IsConst>
struct pointer_to_maybe_const;
template<class T>
struct pointer_to_maybe_const<T, true> { typedef const T* type; };
template<class T>
struct pointer_to_maybe_const<T, false> { typedef T* type; };
template<bool IsConst>
struct C_fields {
typename pointer_to_maybe_const<int, IsConst>::type i;
// repeat for all fields
};
template<class Derived>
class const_C_base {
public:
int method() const { // non-mutating method example
return *self().i;
}
private:
const Derived& self() const { return *static_cast<const Derived*>(this); }
};
template<class Derived>
class C_base : public const_C_base<Derived> {
public:
int method() { // mutating method example
return ++*self().i;
}
private:
Derived& self() { return *static_cast<Derived*>(this); }
};
class const_C : public const_C_base<const_C>, private C_fields<true> {
friend class const_C_base<const_C>;
};
class C : public C_base<C>, private C_fields<false> {
friend class C_base<C>;
};
If you actually have few fields, it may be easier to duplicate them in both classes rather than going for a struct. If there are many, but they are all of the same type, then it is simpler to pass that type as a type parameter directly, and not bother with const wrapper template.
Your example doesn't fail, k is passed by value. The member i is 'implicitly constant' as direct members of C can't be changed when the instance is constant.
Constness says that you can't change members after initialization, but initializing them with values in the initialization list is of course allowed - how else would you give them a value?
What doesn't work is invoking the constructor without making it public though ;)
update addressing updated question:
Yes, C++ forces you into some verboseness sometimes, but const correctness is a common standard behaviour that you can't just redefine without breaking expectations. Pavels answer already explains one common idiom, which is used in proven libraries like the STL, for working around this situation.
Sometimes you have to just accept that languages have limitations and still deal with the expectations of the users of the interface, even if that means applying an apparently sub-optimal solution.
Your question does not make sense. Where did you get all these "this will fail" predictions? None of them are even remotely true.
Firstly, it is completely irrelevant whether the constructor's parameter is declared const or not. When you are passing by value (as in your case) you can pass a const object as an argument in any case, regardless of whether the parameter is declared as const or not.
Secondly, from the constructor's point of view, the object is NOT constant. Regardless of what kind of object you are constructing (constant or not), from within the constructor the object is never constant. So there's no need for mutable or anything.
Why don't you just try compiling your code (to see that nothing will fail), instead of making strange ungrounded predictions that something "will fail"?
A const int* is not the same as a int* const. When your class is const, you have the latter (constant pointer to mutable integer). What you're passing is the former (mutable pointer to constant integer). The two are not interchangeable, for obvious reasons.
When you instantiate
const C c1(...)
Because c1 is const, its member i turns in to:
int* const i;
As someone else mentioned, this is called implicit const.
Now, later in your example, you attempt to pass a const int*. So your constructor is basically doing this:
const int* whatever = ...;
int* const i = whatever; // error
The reason you get an error is because you can't cast const to non-const. The 'whatever' pointer is not allowed to change the thing it points to (the int part is const). The 'i' pointer is allowed to change what it points to, but cannot itself be changed (the pointer part is const).
You also mention wanting your class to model a pointer. The STL does this with iterators. The model some implementations use is having a class called 'const_iterator' which hides the real pointer and only supplies const methods to access the pointed-to data. Then there's also an 'iterator' class which inherits from 'const_iterator', adding non-const overloads. This works nicely - it's a custom class which allows the same constness as pointers, where the types mirror pointers like so:
iterator -> T*
const iterator -> T* const
const_iterator -> const T*
const const_iterator -> const T* const
Hopefully that makes sense :)
OK here's what I have done so far. To allow inheritance after const version of class without const_casts or additional space overhead I created an union which basically looks like ths:
template <typename T>
union MutatedPtr
{
protected:
const T * const_ptr;
T * ptr;
public:
/**
* Conversion constructor.
* #param ptr pointer.
*/
MutatedPtr(const T * ptr): const_ptr(ptr) {};
/**
* Conversion to T *.
*/
operator T *() {return ptr;}
/**
* Conversion to const T *.
*/
operator const T *() const {return const_ptr;}
};
When MutatedPtr field is declared, it ends up so that in const methods const_ptr is returned, while non-const ones get plain ptr. It delegates method's const-ness to pointer target which makes sense in my case.
Any comments?
BTW you can of course do similar thing with non-pointer types or even methods, so it looks that introducing mutable keyword wasn't necessary(?)
I've run into the same unfortunate issue and after lamenting the lack of a const constructor in C++ I've come to the conclusion that two templatization is the best course, at least in terms of reuse.
A very simplified version of my case/solution is:
template< typename DataPtrT >
struct BaseImage
{
BaseImage( const DataPtrT & data ) : m_data( data ) {}
DataPtrT getData() { return m_data; } // notice that if DataPtrT is const
// internally, this will return
// the same const type
DataPtrT m_data;
};
template< typename DataPtrT >
struct DerivedImage : public BaseImage<DataPtrT>
{
};
There is a very unfortunate loss of class inheritance but in my case it was acceptable to make a sort of casting operator to be able to cast between const and non-const types with some explicit knowledge of how to do the conversion under the hood. That mixed with some appropriate use of copy constructors and/or overloaded dereference operator might get you to where you want to be.
template< typename OutTypeT, typename inTypeT )
image_cast< shared_ptr<OutTypeT> >( const shared_ptr<InTypeT> & inImage )
{
return shared_ptr<OutTypeT>( new OutTypeT( inImage->getData() ) );
}