For example, a class with two constructors, one taking a reference and the other taking a string r-value reference.
class A {
public:
A(std::string&& str) {
Foo foo(std::move(str));
//do something with foo. (e.g., use it to initialize some members)
field = foo.bar();
}
A(const std::string& str) {
Foo foo(str);
//do something with foo. (e.g., use it to initialize some members)
field = foo.bar();
}
};
If these two constructors perform virtually the same thing besides std::move appearing in the move constructor, is there any way to avoid having two nearly identical chunks of code?
The first option is to use templated constructor:
class A
{
public:
template<typename T, typename = std::enable_if<std::is_same<std::remove_reference<T>::type, std::string>::value>::type>
A(T && str) {
Foo foo(std::forward<T>(str));
//do something
}
};
But it looks a bit ugly. If Foo(const std::string &) actually makes a copy of string, then I'd prefer to pass the parameter by value:
class A
{
public:
A(std::string str) {
Foo foo(std::move(str));
//do something
}
};
The overhead of this approach is additional move constructor.
But don't be bothered of it because the compiler is likely to optimize it.
Accept by value. That will do the trick of doing the same thing as both.
Obvious answer: make a third fn which performs the common part, which is called from both the other fns.
You may be able to directly call one from the other, but it would depend on the nature of the data stored within the class and what is being referenced. However, in many cases a copy constructor can be used to implement move, if desired, though not as efficiently.
You can do this using universal references, but only in the cases where the constructor is templated.
class A {
public:
template<typename T>
A(T && str) {
Foo foo(std::forward<T>(str));
//do something
}
};
Related
Suppose I have a class with some constant member:
class MyClass {
public:
MyClass(int a) : a(a) {
}
MyClass() : MyClass(0) {
}
~MyClass() {
}
const int a;
};
Now I want to store an instance of MyClass somewhere, e.g. as a global variable or as an attribute of another object.
MyClass var;
Later, I want to assign a value to var:
var = MyClass(5);
Obviously, this does not work, because the assign operator is invoked, which does not exist by default, because MyClass has a const attribute. So far so good.
My question is, how can I assign a value to var anyway? After all, var itself is not declared to be a constant.
My thoughts so far
I know that the problem does not exist if I use a pointer for var:
MyClass *var;
var = new MyClass(5);
However, I would not like to use a pointer for convenience reasons.
A potential solution is to overwrite the memory with placement new:
template<class T, class... Args>
T &emplaceVar(T &myVar, Args&&... args) {
myVar.~T(); // free internal memory
return *new (&myVar) T(args...);
}
emplaceVar(var, 5);
This would solve the problem, but I am not sure if this may cause memory leaks or any other issues I have not thought of due to my lack of experience in c++. Furthermore, I would have thought there must be an easier way. Is there?
const members are problematic in general for the very reason you discovered.
The much simpler alternative is to make the member private and take care to provide no means to modify it from outside the class:
class MyClass {
public:
MyClass(int a) : a(a) {
}
MyClass() : MyClass(0) {
}
~MyClass() {
}
private:
int a;
};
I did not add a getter yet, because you say access via myObject.a is a hard requirement. Enabling this requires a bit of boilerplate, but it is much less hacky than modifiying something that must not be modified:
class MyClass {
public:
struct property {
const int& value;
operator int(){ return value;}
property(const property&) = delete;
};
MyClass(int a = 0) : value(a) {}
private:
int value;
public:
property a{value};
};
int main(){
MyClass myObject{5};
int x = myObject.a;
//myObject.a = 42; // error
//auto y = myObject.a; // unexpected type :/
}
Live Demo
Drawback is that it does not play well with auto. If by any means you can accept myObject.a() I would suggest to use that and keep it simple.
how can I assign a value to var anyway?
You can do that with a user-defined assignment operator:
class MyClass {
public:
MyClass &operator=(const MyClass &o)
{
// Implement your assignment here
return *this;
}
// ...
};
Your assignment operator can do anything that any operator= overload can. The only thing it can't do is assign anything to its const class member. That's because it's constant.
If a class does not have user-defined assignment operator, the default assignment operator assigns each member of the assigned-to object from the same member of the assigned-from object. However the default assignment operator is deleted from any class that has a const member, because that, of course, is no longer possible.
In your user-defined operator you can do whatever it means to assign one of these objects from another one. The only thing it can't do is the same thing any other class method can't do: modify a const class member.
You mentioned manual invocation of a destructor and placement new. That's possible, provided that all requisite requirements are met and undefined behavior is carefully avoided. However, technically, it wouldn't be assignment, but rather a manual destruction and construction of another object.
I have some classes that look like this:
struct foo
{
foo() = delete;
explicit foo(int id) :
id(id)
{}
virtual ~foo() = default;
int id;
};
template<typename T>
struct MyClass : foo
{
MyClass() = delete;
MyClass(int id, T value) :
foo(id),
value(value)
{}
T value;
}
And it has worked pretty well up until now where T is a double, a bool, etc.
Unfortunately, CPU manufacturers decided to start putting more logical cores in their products, and now I have to write a bunch of multithreaded code (thanks guys).
The problem arises when trying to do something like
MyClass<std::atomic_flag> bar{0, ?????????????} //ATOMIC_FLAG_INIT doesnt fix it
As it attempts to use the deleted copy constructor std::atomic_flag(const std::atomic_flag&). I can see where its trying to do the copy, and the only possible solution I've come up with would involve manual allocation of memory and almost by-hand construction of members using placement-new.
Is there an easier way of doing this? How might the constructor of MyClass<T> be structured to allow generic types as well as special things that don't want to be moved/copied?
I'm using MSVC v140, so no C++17 or later features :(
Rather than taking an instance of the object to create, you can construct it inside your object by instead taking parameters of the type you wish to construct your class with. This will not work directly with std::atomic_flag due to the limitations of initializing with ATOMIC_FLAG_INIT (until C++20, that is), but would be fine with something like std::atomic<bool>.
For example:
template <typename T>
struct MyClass : foo {
MyClass() = delete;
// list of parameters to pass to value's constructor
// if this is only going to be with primitive-like types,
// you could take Args by value instead of forwarding reference
template <typename... Args>
explicit MyClass(int id, Args&&... args)
: foo(id), value(std::forward<Args>(args)...)
{}
T value;
};
Then you should be able to do
MyClass<std::atomic<bool>> bar{0, false};
I want to pass a std::unique_ptr to the constructor of a class that will take ownership of the data owned by the std::unique_ptr.
Are there any differences between the approaches foo and bar below in terms of how the compiler handles them that would make one of them preferable?
foo class:
template <class T>
class foo
{
std::unique_ptr<T> data_;
public:
foo(std::unique_ptr<T>&& data) :
data_{ std::forward<std::unique_ptr<T>>(data) }
{
}
};
bar class:
template <class T>
class bar
{
std::unique_ptr<T> data_;
public:
bar(std::unique_ptr<T> data) :
data_{ std::move(data) }
{
}
};
Binding to a reference requires one less move:
void f(std::unique_ptr<T>&& p) { g(std::move(p)); }
f(std::make_unique<T>()); // no move, g binds directly to the temporary
Binding to an object parameter requires one actual move:
void f(std::unique_ptr<T> p) { g(std::move(p)); }
f(std::make_unique<T>()); // p constructed (= moved) from temporary,
// g binds to p
The extra move involves one pointer copy, one setting of a pointer to null, and one destructor with a condition check. This is not a big cost, and the question of which style to use depends on the kind of code you're writing:
The more leaf your code is and the less it is used, the more the simple version with by-value passing buys you simplicity. Conversely, the more library your code is and the less you know your users, the more there is value in not imposing avoidable cost, no matter how small.
You decide.
I have C++ code that boils down to something like the following:
class Foo{
bool bar;
bool baz;
Foo(const void*);
};
Foo::Foo(const void* ptr){
const struct my_struct* s = complex_method(ptr);
bar = calculate_bar(s);
baz = calculate_baz(s);
}
Semantically, the bar and baz member variables should be const, since they should not change after initialization. However, it seems that in order to make them so, I would need to initialize them in an initialization list rather than assign them. To be clear, I understand why I need to do this. The problem is, I can't seem to find any way to convert the code into an initialization list without doing one of the following undesirable things:
Call complex_method twice (would be bad for performance)
Add the pointer to the Foo class (would make the class size needlessly large)
Is there any way to make the variables const while avoiding these undesirable situations?
If you can afford a C++11 compiler, consider delegating constructors:
class Foo
{
// ...
bool const bar;
bool const baz;
Foo(void const*);
// ...
Foo(my_struct const* s); // Possibly private
};
Foo::Foo(void const* ptr)
: Foo{complex_method(ptr)}
{
}
// ...
Foo::Foo(my_struct const* s)
: bar{calculate_bar(s)}
, baz{calculate_baz(s)}
{
}
As a general advice, be careful declaring your data members as const, because this makes your class impossible to copy-assign and move-assign. If your class is supposed to be used with value semantics, those operations become desirable. If that's not the case, you can disregard this note.
One option is a C++11 delegating constructor, as discussed in other answers. The C++03-compatible method is to use a subobject:
class Foo{
struct subobject {
const bool bar;
const bool baz;
subobject(const struct my_struct* s)
: bar(calculate_bar(s))
, baz(calculate_baz(s))
{}
} subobject;
Foo(const void*);
};
Foo::Foo(const void* ptr)
: subobject(complex_method(ptr))
{}
You can make bar and baz const, or make the subobject const, or both.
If you make only subobject const, then you can calculate complex_method and assign to bar and baz within the constructor of subobject:
class Foo{
const struct subobject {
bool bar;
bool baz;
subobject(const void*);
} subobject;
Foo(const void*);
};
Foo::Foo(const void* ptr)
: subobject(ptr)
{}
Foo::subobject::subobject(const void* ptr){
const struct my_struct* s = complex_method(ptr);
bar = calculate_bar(s);
baz = calculate_baz(s);
}
The reason that you can't mutate const members within a constructor body is that a constructor body is treated just like any other member function body, for consistency. Note that you can move code from a constructor into a member function for refactoring, and the factored-out member function doesn't need any special treatment.
You may use delegate constructor in C++11:
class Foo{
public:
Foo(const void* ptr) : Foo(complex_method(ptr)) {}
private:
Foo(const my_struct* s) : bar(calculate_bar(s)), baz(calculate_baz(s)) {}
private:
const bool bar;
const bool baz;
};
If you don't want to use the newfangled delegating constructors (I still have to deal with compiler versions that don't know about them), and you don't want to change the layout of your class, you could opt for a solution that replaces the constructor with const void * argument by a static member function returning Foo, while having a private constructor that takes the output from complex_method as argument (that latter much like the delegating constructor examples). The static member function then does the necessary preliminary computation involving complex_method, and ends with return Foo(s);. This does require that the class have an accessible copy constructor, even though its call (in the return statement) can most probably be elided.
I feel like this one has been asked before, but I'm unable to find it on SO, nor can I find anything useful on Google. Maybe "covariant" isn't the word I'm looking for, but this concept is very similar to covariant return types on functions, so I think it's probably correct. Here's what I want to do and it gives me a compiler error:
class Base;
class Derived : public Base;
SmartPtr<Derived> d = new Derived;
SmartPtr<Base> b = d; // compiler error
Assume those classes are fully fleshed out... I think you get the idea. It can't convert a SmartPtr<Derived> into a SmartPtr<Base> for some unclear reason. I recall that this is normal in C++ and many other languages, though at the moment I can't remember why.
My root question is: what is the best way to perform this assignment operation? Currently, I'm pulling the pointer out of the SmartPtr, explicitly upcasting it to the base type, then wrapping it in a new SmartPtr of the appropriate type (note that this is not leaking resources because our home-grown SmartPtr class uses intrusive reference counting). That's long and messy, especially when I then need to wrap the SmartPtr in yet another object... any shortcuts?
SmartPtr<Base> and SmartPtr<Derived> are two distinct instantiations of a the SmartPtr template. These new classes do not share the inheritance that Base and Derived do. Hence, your problem.
what is the best way to perform this assignment operation?
SmartPtr<Base> b = d;
Does not invoke assignment operator. This invokes the copy-ctor (the copy is elided in most cases) and is exactly as if you wrote:
SmartPtr<Base> b(d);
Provide for a copy-ctor that takes a SmartPtr<OtherType> and implement it. Same goes for the assignment operator. You will have to write out the copy-ctor and op= keeping in mind the semantics of SmartPtr.
Both the copy constructor and the assignment operator should be able to take a SmartPtr of a different type and attempt to copy the pointer from one to the other. If the types aren't compatible, the compiler will complain, and if they are compatible, you've solved your problem. Something like this:
template<class Type> class SmartPtr
{
....
template<class OtherType> SmartPtr(const SmartPtr<OtherType> &blah) // same logic as the SmartPtr<Type> copy constructor
template<class OtherType> SmartPtr<Type> &operator=(const SmartPtr<OtherType> &blah) // same logic as the SmartPtr<Type> assignment operator
};
Templates are not covariant, and that's good; imagine what would happen in the following case:
vector<Apple*> va;
va.push_back(new Apple);
// Now, if templates were covariants, a vector<Apple*> could be
// cast to a vector<Fruit*>
vector<Fruit*> & vf = va;
vf.push_back(new Orange); // Bam, we just added an Orange among the Apples!
To achieve what you are trying to do, the SmartPointer class must have a templatized constructor, that takes either another SmartPointer or a pointer of another type. You could have a look at boost::shared_ptr, which does exactly that.
template <typename T>
class SmartPointer {
T * ptr;
public:
SmartPointer(T * p) : ptr(p) {}
SmartPointer(const SmartPointer & sp) : ptr(sp.ptr) {}
template <typename U>
SmartPointer(U * p) : ptr(p) {}
template <typename U>
SmartPointer(const SmartPointer<U> & sp) : ptr(sp.ptr) {}
// Do the same for operator= (even though it's not used in your example)
};
Depends on the SmartPtr class. If it has a copy constructor (or in your case, assignment operator) that takes SmartPtr<T>, where T is the type it was constructed with, then it isn't going to work, because SmartPtr<T1> is unrelated to SmartPtr<T2> even if T1 and T2 are related by inheritance.
However, if SmartPtr has a templatized copy constructor/assignment operator, with template parameter TOther, that accepts SmartPtr<TOther>, then it should work.
Assuming you have control of the SmartPtr class, the solution is to provide a templated constructor:
template <class T>
class SmartPtr
{
T *ptr;
public:
// Note that this IS NOT a copy constructor, just another constructor that takes
// a similar looking class.
template <class O>
SmartPtr(const SmartPtr<O> &src)
{
ptr = src.GetPtr();
}
// And likewise with assignment operator.
};
If the T and O types are compatible, it will work, if they aren't you'll get a compile error.
I think the easiest thing is to provide automatic conversion to another SmartPtr according to the following:
template <class T>
class SmartPtr
{
public:
SmartPtr(T *ptr) { t = ptr; }
operator T * () const { return t; }
template <class Q> operator SmartPtr<Q> () const
{ return SmartPtr<Q>(static_cast<Q *>(static_cast<T *>(* this))); }
private:
T *t;
};
Note that this implementation is robust in the sense that the conversion operator template does not need to know about the semantics of the smart pointer, so reference counting does not need to replicated etc.