I have the following setup:
class MyClass {
public:
static MyClass Clone(const MyClass& other) {
return MyClass(other, 10);
}
static MyClass CreateNormal(int x, int y) {
return MyClass(int x, int y);
}
// There are a few more factory functions.
private:
// Constructor 1
MyClass(int x, int y) : b_(x, y) {}
// Constructor 2
MyClass(const MyClass& other, int c) : b_(other.b_, c) {}
// And a lot more constructors.
// NotMyClass has its copy constructor deleted.
NotMyClass b_;
}
int main() {
MyClass A(1,2);
MyClass B = MyClass::Clone(A); // ERROR
}
Is there a way to get around this without modifying NotMyClass?
The error happens because the copy constructor of MyClass is implicitly deleted. Is there a way I can use std::Move() to solve this?
I cannot remove the factory functions as the actual class has many constructors and the factory functions are needed for clarity and understanding.
Assuming the availability of the c++11 standard, you could extend the lifetime of the rvalue reference returned by the factory method instead of constructing a new object, like so:
MyClass A(1, 2);
MyClass&& B = MyClass::Clone(A);
Addendum:
As noted by patatahooligan in a comment below, there might be a copy constructor invocation in your version of MyClass::Clone itself. This can/needs to be rewritten to
MyClass MyClass::Clone(const MyClass& other) {
return {other, 10};
}
All of this will be completely unecessary once C++17 comes with mandatory copy-elision comes around, so you can look forward to that.
In C++03 it is still possible to achive the desired outcome albeit the solutions are longer and require more code. I offer two alternatives:
Instead of creating a set of static methods, I would advise for using tag-dispatch to signal different constructor meanings. This works by overloading the constructor with type arguments which have clear names but hold no data.
struct clone_tag {};
class MyClass {
public:
MyClass(int x, int y) : b_(x, y) {}
MyClass(const MyClass& self, clone_tag) : b_(self.b_, 10) {}
private:
NotMyClass b_;
};
int main() {
MyClass A(1, 2);
MyClass B(A, clone_tag());
}
Or this could even go as far as a genuine factory pattern, where the building the factory and final construction of the object is seperated. This clearly needs more time to set up but could improve code quality, depending on the actual number of different constructor paths.
class MyClass {
public:
struct Clone {
Clone(const MyClass& self) : self(self) {}
const MyClass& self;
};
struct Init {
Init(int x, int y) : x(x), y(y) {}
int x, y;
};
MyClass(Init i) : b_(i.x, i.y) {}
MyClass(Clone c) : b_(c.self.b_ , 10) {}
private:
MyClass(const MyClass& other, int c) : b_(other.b_, c) {}
NotMyClass b_;
};
int main() {
MyClass A = MyClass::Init(1, 2);
MyClass B = MyClass::Clone(A);
}
On second thought I realize that giving three different alternatives could cause more confusion than a short answer which is less precise. I therefore tried to list them in order of needed refactoring work although this is only guess work about your real code base.
Related
I must create a code that uses an explicit constructor to convert a int type to an existing class.
class MyClass
{public:
MyClass(int& obj); //I tried to use a syntax similar to a copy construct
}
int a;
MyClass a();
class MyClass
{
private:
int m_value;
public:
explicit MyClass(int value) : m_value(value) {}
};
int a = ...;
MyClass obj(a);
This question already has answers here:
Explicit copy constructor
(3 answers)
Closed 3 years ago.
I came across this curio and don't understand why the use of explicit constructors would cause this to fail.
I was trying to generate and initialize objects from configuration data using lambdas. I found that the lambda could only return a copy of the object if the object's class definition did not use explicit constructors. This code sample is a simplistic example of what I found.
class foo {
public:
explicit foo() : _a(0) {}
explicit foo(int val): _a(val) {}
explicit foo(const foo& o) : _a(o._a) {}
explicit foo(foo&& o) : _a(std::move(o._a)) {}
foo& operator()(const foo& rhs) { if (this != &rhs) { _a = rhs._a; } return *this; }
foo& operator()(foo&& rhs) { _a = std::move(rhs._a); return *this; }
int a() const { return _a; }
void a(int val) { _a = val; }
private:
int _a;
};
auto makeFoo = [](int val) -> foo { return foo(val); };
As written the sample code fails to compile with the following errors on the makeFoo line:
In static member function ‘static foo<lambda(int)>::_FUN(int)’:
error: no matching function for call to ‘foo::foo(foo)’
However, if I remove the 'explicit' tags from the foo constructors, the code compiles just fine.
Can someone enlighten me as to why the constructors cannot be explicit in this lambda?
First of all, review the documentation about the explicit keyword.
Specifies that a constructor or conversion function (since C++11) is explicit, that is, it cannot be used for implicit conversions and copy-initialization.
Basically, the explicit copy constructor means that the copy constructor will not be called implicitly.
You don't need to define your copy/move constructor, the compiler will generate them for you. Same for the copy/move assignment. Just remove them and you will be fine.
class foo {
public:
foo() = default;
explicit foo(int val): _a(val) {}
int a() const { return _a; }
void a(int val) { _a = val; }
private:
int _a{0};
};
I need a workaround or a nice solution for initializing a bunch of constant class variables in base and subclass
The problem is simple, I got a baseclass with two constructor and the same two constructor in the subclass
class BASE {
int a;
int func(float x) { // just a dummy to show that this function
return (a = (int) x) + 2; // modifies a
}
public:
const int b;
BASE(const int b) : b(b) {} // doesn't use a
BASE(const float x) : a(0), b(func(x)) {}
};
struct SUB: public BASE {
const int c;
const int d;
SUB(const int b) : BASE(b), c(b), d(c + 3) {}
SUB(const float x) : BASE(x), c(b), d(c + 3) {}
};
The subclass needs to call the constructor from BASE to initialize the class variables from BASE after that the sub class initialize the remaining variables
So far so good but the problem is that both constructor from SUB do the exactly same except calling a different constructor from BASE
I want something like that
SUB() : c(b), d(c + 3) {} // BASE() needs to be defined
SUB(const int b) : BASE(b), SUB() {}
SUB(const float x) : BASE(x), SUB() {}
but that doesn't work because "a call to a delegating constructor shall be the only member-initializer" ...
Moving everything outside the initializer list doesn't work because these are const class variables
You can create a "forwarding constructor" for your derived class:
struct SUB: public BASE {
const int c;
const int d;
template <class... T>
SUB(T&&... a) : BASE(std::forward<T>(a)...), c(b), d(c + 3) {}
};
This will accept arbitrary arguments and forward them on to BASE. Of course, it will only compile when called with arguments which are valid for BASE, but that holds for every case.
If you want/need to be super-correct, you can condition the constructor using SFINAE on somethin like std::is_constructible<BASE, T&&...>, but I wouldn't bother.
Unfortunately that's the rules of the language, if you have a delegating constructor it must be the only part of the initializer list.
You need to work around that limitation, for example by duplicating the default constructor initializer list:
SUB(const int b) : BASE(b), c(b), d(c + 3) {}
I have a class Foo that has a reference to Bar as an instance variable. Is there a way to have one of the Foo constructors create a Bar instance (so users of the Foo class need not explicitly create a Bar object themselves)?
I'd like to do something like this:
class Foo {
private:
int size;
Bar& bar; // shared by other objects
//several other instance variables
public:
Foo(int s, Bar& b) : size(s), bar(b) {}
// This, of course, doesn't work. I can't think of an
// alternative that doesn't require users of Foo to
// create Bar
Foo(int s) : size(s), bar(Bar(s)) {}
}
(In "real life", Foo and Bar are more complicated. Bar is a friend of Foo that has a private constructor used only by Foo. Each Bar can be shared by several Foos. This isn't a major problem, I'm just curious if it can be done without pointers.)
The simplest solution would be to allocate a Bar if and when you need one. Adding a member std::unique_ptr<Bar> is the easiest way of achieving this. I can't conceive of a system that addresses your problem that will not add some memory overhead to your class. You either have to account for storage for a Bar even when it isn't needed or you have to account for some state to track rather or not your Bar is internally managed. Using a unique_ptr adds the size of a pointer to your class.
#include <memory>
class Foo {
private:
std::unique_ptr<Bar> storage;
Bar& bar;
int size;
public:
Foo(int s, Bar& b) : bar(b), size(s) {}
Foo(int s) : storage(std::make_unique<Bar>(s)), bar(*storage), size(s) {}
};
A more elaborate solution could be to provide a wrapper for Bar that provides a default constructor that takes care of initializing a new instance.
Note that in your example, you do not initialize the member in the same order as they are declared. Members will be initialized in the order they are declared regardless of how you order them in your initialization list.
If every Foo shall have it's own individual Bar-object (not a single shared one), then you could try the following:
class Foo {
private:
Bar& bar; // shared by other objects
int size;
Bar* defaultBar;
//several other instance variables
public:
Foo(int s, Bar& b) : size(s), bar(b), defaultBar(nullptr) {}
Foo(int s) : Foo(s, *(new Bar(14))) { defaultBar=&bar; };
virtual ~Foo() {
if (defaultBar)
delete defaultBar;
}
void setBar(Bar &b) {
if (defaultBar)
delete defaultBar;
defaultBar = nullptr;
bar=b;
}
};
Hope it is what you are looking for.
// This, of course, doesn't work. I can't think of an
// alternative that doesn't require users of Foo to
// create Bar
Foo(int s) : size(s), bar(Bar(14)) {}
You can use a default Bar object, which can be a static member variable of Foo or any other class that can provide such an object.
E.g.
class Foo {
private:
Bar& bar; // shared by other objects
int size;
//several other instance variables
static Bar& getDefaultBar();
public:
Foo(int s, Bar& b) : size(s), bar(b) {}
Foo(int s) : size(s), bar(getDefaultBar()) {}
}
Bar& Foo::getDefaultBar()
{
static Bar b(24);
return b;
}
While creating object we can have implicit or explicit call to constructor
Base obj;
Base obj = Base(1,2);
Both these object creation methods are working fine, until I include copy constructor in code.
Here is the code snippet.
#include<iostream>
using namespace std;
class Base {
public:
Base(int x, int y) {}
Base() {}
Base(Base& o){}
private:
int a;
int b;
};
int main() {
Base obj = Base(10,20); /*This line throws error after including copy Ctor*/
Base obj2 = obj;
}
I am using Linux g++ compiler.
Error : no matching function for call to ‘Base::Base(Base)’
Am I missing something.
Copy Constructor should be of following form, to enable the temporary object creation with Base(10,20)
Base(const Base& o){}
// ~~~~ notice `const`
Alternatively, you can use move constructor with C++11, to allow temporary objects
Base(Base &&o){}
You have two possibilities. Either change the declaration of the copy constructor like
Base( const Base &o){}
Or add a move constructor
Base(Base &&o){}
For example
#include<iostream>
using namespace std;
class Base {
public:
Base(int x, int y) {}
Base() {}
Base(Base& o){}
Base( Base && ){}
private:
int a;
int b;
};
int main() {
Base obj = Base(10,20); /*This line throws error after including copy Ctor*/
Base obj2 = obj;
}
The problem with your code is that expression Base(10,20) creates a temporary object that can be binded only with a constant reference.
in fact you need not to define the copy constructor explicitly for this simple class.