Below is a downsized implementation of a two classes I'm having trouble with.
code:
Here is the base class:
//header
class Script
{
public:
Script(const QString& path, int timeout=10000) :
mPath(path), mTimeout(timeout), script(new QProcess) {}
Script(Script&& s);
Script& operator=(Script&& s);
virtual ~Script();
protected:
QString mPath;
int mTimeout;
QProcess* script;
}
//source
Script::Script(Script&& s) :
mPath(s.mPath), mTimeout(s.Timeout), script(s.script)
{
s.script = nullptr;
}
Script& Script::operator=(Script&& s){
if(&s != this){
delete script;
script = s.script;
s.script = nullptr;
mPath = s.mPath;
mTimeout = s.mTimeout;
}
return *this;
}
Script::~Script() {
delete script;
script = nullptr;
}
From the code snippet above I derive the following class:
//header
class ConfigurationScript : public Script
{
public:
ConfigurationScript(const QString& path);
ConfigurationScript(ConfigurationScript&& s);
ConfigurationScript& operator=(ConfigurationScript&& s);
}
//source
ConfigurationScript::ConfigurationScript(const QString& path) :
Script(path) {}
ConfigurationScript::ConfigurationScript(ConfigurationScript&& s) :
Script(std::move(s)) {}
ConfiguratonScript& ConfigurationScript::operator=(ConfigurationScript&& s) {
if(&s != this){
delete script;
script = s.script;
s.script = nullptr;
mPath = s.mPath;
mTimeout = s.mTimeout;
}
return *this;
}
question:
The move assignment of ConfigurationScript contains duplicate code when you compare it to the move assignment of its base class Script. Can you call the assignment operator of the base class to overcome duplicate code?
For instance is something like this valid?
ConfigurationScript& ConfigurationScript::operator=(ConfigurationScript&& s) {
if(&s != this){
Script::operator=(s);
}
return *this;
}
The return type of Script::operator=(s) is Script, do I need to cast it to a ConfigurationScript?
If the above is valid, I fail to see how it works. Otherwise, is there a way to avoid code duplication?
Yes, it's valid, and you don't need to cast anything.
You're not even using the result of the base op= call, but you know that it is a Script& that refers to the current object. Since you already have a ConfigurationScript& that refers to the current object and has the needed type (i.e. *this), there is nothing more to do.
In fact, this is so natural that you can just let the compiler do it for you:
#include <iostream>
#include <utility>
struct Base
{
Base& operator=(Base&& other)
{
std::cout << "YOLO!\n";
return *this;
}
};
struct Derived : Base
{
/*
// Don't need this
Derived& operator=(Derived&& other)
{
Base::operator=(std::move(other));
return *this;
}*/
/*
// Or even this (though you may need to introduce it
// if you have some other user-declared stuff)
Derived& operator=(Derived&& other) = default;
*/
};
int main()
{
Derived d1, d2;
d2 = std::move(d1);
}
// Output: YOLO!
(live demo)
However I think you probably meant Script::operator=(std::move(s)) to get true movement rather than a copy.
Related
I want to write a class that uses the PIMPL idiom but makes the following possible:
int main() {
MyClass myclass {12};
std::string val = myclass.get_value();
std::cout << val << "\n";
MyClass copy = myclass;
val = copy.get_value();
return 0;
}
That is, provide copy functionality while using PIMPL. Using std::unique_ptr to implement PIMPL leads to the expected compile error:
error C2280: 'MyClass::MyClass(const MyClass &)': attempting to reference a deleted function
This is my attempt:
class.hpp
#pragma once
#include <string>
#include "copyable_unique_ptr.hpp"
class MyClass {
private:
struct MyClassPrivate;
copyable_unique_ptr<MyClassPrivate> _impl;
public:
MyClass(int value);
~MyClass();
std::string get_value();
};
class.cpp
#include "class.hpp"
#include <string>
struct MyClass::MyClassPrivate {
int value;
};
MyClass::MyClass(int value)
: _impl(std::make_unique<MyClassPrivate>()) {
_impl->value = value;
}
MyClass::~MyClass() = default;
std::string MyClass::get_value() {
return std::to_string(_impl->value);
}
copyable_unique_ptr.hpp
#pragma once
#include <memory>
template <typename T>
class copyable_unique_ptr {
private:
std::unique_ptr<T> _ptr;
public:
copyable_unique_ptr(std::unique_ptr<T> &&ptr)
: _ptr(std::move(ptr)) {}
~copyable_unique_ptr() = default;
copyable_unique_ptr(const copyable_unique_ptr<T> &other) {
_ptr = std::make_unique<T>(*other._ptr);
}
copyable_unique_ptr(copyable_unique_ptr<T> &&other) {
_ptr = std::move(other._ptr);
}
copyable_unique_ptr &operator=(const copyable_unique_ptr<T> &other) {
_ptr = std::make_unique<T>(*other._ptr);
}
copyable_unique_ptr &operator=(copyable_unique_ptr<T> &&other) {
_ptr = std::move(other._ptr);
}
T *operator->() {
return _ptr.get();
}
};
which leads to the following error:
warning C4150: deletion of pointer to incomplete type 'MyClass::MyClassPrivate'; no destructor called
I also had this error when first trying to use unique_ptr, and the solution was to move the destructor into class.cpp: MyClass::~MyClass() = default;.
I don't really know how to solve this problem while using the approach with copyable_unique_ptr.
I saw this question on SO. They are trying to do the same as me, but the last comment to the answer suggests that they are having exactly the same problem.
Although you can write a custom smart pointer here, I always like to reuse as much code as possible. It seems you want a dynamically created object with copy semantics rather than pointer semantics. For that reason I would hesitate to call your copyable_unique_ptr a pointer at all. I did write a class for this once and settled on something like dynamic_object<T>.
Instead of a pointer I would do this using a std::vector that contains just a single element. Something a bit like this:
class MyClass {
private:
struct MyClassPrivate;
std::vector<MyClassPrivate> _impl;
public:
MyClass(int value);
~MyClass();
std::string get_value();
};
struct MyClass::MyClassPrivate {
int value;
};
MyClass::MyClass(int value)
: _impl(1) {
_impl.front().value = value;
}
MyClass::~MyClass() = default;
std::string MyClass::get_value() {
return std::to_string(_impl.front().value);
}
However if you really want to create your copyable_unique_ptr I woud still use a std::vector here to simplify its codeing and to reuse high quality Standard Library code:
Perhaps a bit like this:
template<typename T>
class copyable_unique_ptr
: private std::vector<T>
{
using base_type = std::vector<T>;
public:
copyable_unique_ptr(std::unique_ptr<T>&& ptr)
: base_type(std::move(*ptr), 1) {}
copyable_unique_ptr(std::unique_ptr<T> const& ptr)
: base_type(*ptr, 1) {}
T& operator*() { return base_type::back(); }
T* operator->() { return base_type::data(); }
T const& operator*() const { return base_type::back(); }
T const* operator->() const { return base_type::data(); }
};
Sam Varshavchik gave a hint in the comment that also moving copy constructor and assignment operator to the implementation fixes the code that I was trying to write, that means:
class.hpp
#pragma once
#include <string>
#include "copyable_unique_ptr.hpp"
class MyClass {
private:
struct MyClassPrivate;
copyable_unique_ptr<MyClassPrivate> _impl;
public:
MyClass(int value);
MyClass(const MyClass &);
MyClass(MyClass &&);
MyClass &operator=(const MyClass &);
MyClass &operator=(MyClass &&);
~MyClass();
std::string get_value();
};
class.cpp
#include "class.hpp"
#include <string>
#include <iostream>
struct MyClass::MyClassPrivate {
int value;
};
MyClass::MyClass(int value)
: _impl(std::make_unique<MyClassPrivate>()) {
_impl->value = value;
}
MyClass::MyClass(const MyClass &) = default;
MyClass::MyClass(MyClass &&) = default;
MyClass &MyClass::operator=(const MyClass &) = default;
MyClass &MyClass::operator=(MyClass &&) = default;
MyClass::~MyClass() = default;
std::string MyClass::get_value() {
std::cout << &_impl << "\n";
return std::to_string(_impl->value);
}
And it works as expected.
On the other hand, Galik gave an answer that gives a much better and less complex alternative to copyable_unique_ptr. I will prefer using his way.
Its probably simpler to stick to a normal unique_ptr and just implement copying of MyClass in your cpp file:
class MyClass {
private:
struct MyClassPrivate;
std::unique_ptr<MyClassPrivate> _impl;
public:
MyClass(int value);
MyClass(MyClass&&);
MyClass(const MyClass&);
~MyClass();
MyClass& operator = (const MyClass&);
MyClass& operator = (MyClass&&);
std::string get_value();
};
MyClass::MyClass(const MyClass& other)
: _impl(std::make_unique<MyClassPrivate>(*other._impl)) {
}
MyClass& MyClass::operator = (const MyClass& other) {
_impl = std::make_unique<MyClassPrivate>(*other._impl);
return *this;
}
MyClass::~MyClass() = default;
MyClass::MyClass(MyClass&&) = default;
MyClass& MyClass::operator = (MyClass&&) = default;
There is a slight issue with this code (and your original code) in that the moved from objects will have a null _impl you might want to add checks for null, alternatively you could replace with a default constructed object instead of a null pointer but that might be a waste in most cases?
How can I delete all the pointer in my vector before that I going to copy to my vector new pointers (in case of const object)?
class Element {
int val;
public:
Element(int val) :
val(val) {
}
};
class MyClass {
vector<Element*> v;
static void FreeMemory(vector<Element*>& vec) {
for (unsigned int i = 0; i < vec.size(); i++) {
delete vec[i];
}
}
public:
MyClass() = default;
MyClass(const MyClass& mc) {
//...
}
MyClass& operator=(const MyClass& mc) {
if (this == &mc) {
return *this;
}
//...
FreeMemory(mc.v); //**error** - how can I delete the memory of any Element?
//...
return *this;
}
// ....
// ....
};
binding 'const std::vector' to reference of type 'std::vector&' discards qualifiers
Can I fix it with smart_pointers?
Here is a sketch of a class owning a std::vector of Element objects managed by std::unique_ptr. Not fully worked out, but it might work as a starting point.
class Element {
int val;
public:
explicit Element(int val) : val(val) {}
virtual ~Element() = default;
/* Subclasses must implement this method: */
virtual std::unique_ptr<Element> clone() const = 0;
};
class ExclusivelyOwning {
private:
std::vector<std::unique_ptr<Element>> v;
public:
ExclusivelyOwning() = default;
ExclusivelyOwning(const ExclusivelyOwning& other) {
v.reserve(other.v.size());
for (const auto& element : other.v)
v.push_back(element->clone());
}
ExclusivelyOwning& operator=(const ExclusivelyOwning& rhs) {
/* Use copy-swap idiom, not shown here. */
return *this;
}
ExclusivelyOwning(ExclusivelyOwning&&) = default;
ExclusivelyOwning& operator = (ExclusivelyOwning&&) = default;
~ExclusivelyOwning() = default;
};
Note that copying an object with references to abstract classes (as Element in the code above) requires further techniques to render the copying meaningful. Here, I used a "virtual constructor" - the clone method.
I want to start throwing some interfaces into my C++ code to make it easier for me to unit test using mocks.
The problem with this is returning abstract classes from a method in C++ is a pain. You can't return by value so you need to return a pointer or a reference.
Given all of the developments in C++ in the last six or seven years, I thought I'd ask if maybe we had a better way to return an abstract base class. An interface without the noise would look something like this, but I'm sure this isn't possible.
IBaseInterface getThing() {return DerivedThing{};}
The way that I remember doing this in the past is to use a pointer (probably a smart pointer now):
std::unique_ptr<IBaseInterface> getThing() {return std::make_unique<DerivedThing>();}
The problem with the pointer is that I'm never actually planning to take advantage of nullptr so the overhead and noise of dealing with a pointer rather than a value gains me no value as a reader.
Is there a better way that I don't know to handle this?
EDIT: provides complete example, including making the polymorphic handle copyable.
#include <iostream>
#include <utility>
#include <memory>
struct IBaseInterface {
IBaseInterface() = default;
IBaseInterface(IBaseInterface const&) = default;
IBaseInterface(IBaseInterface &&) = default;
IBaseInterface& operator=(IBaseInterface const&) = default;
IBaseInterface& operator=(IBaseInterface &&) = default;
virtual ~IBaseInterface() = default;
virtual std::unique_ptr<IBaseInterface> clone() const = 0;
virtual void do_thing() = 0;
};
struct handle
{
handle(std::unique_ptr<IBaseInterface> ptr)
: _impl(std::move(ptr))
{}
handle(handle const& r)
: _impl(r._impl->clone())
{}
handle(handle && r)
: _impl(std::move(r._impl))
{}
handle& operator=(handle const& r)
{
auto tmp = r;
std::swap(_impl, tmp._impl);
return *this;
}
handle& operator=(handle && r)
{
_impl = std::move(r._impl);
return *this;
}
// interface here
void do_thing() { _impl->do_thing(); }
private:
std::unique_ptr<IBaseInterface> _impl;
};
struct DerivedThing : IBaseInterface
{
std::unique_ptr<IBaseInterface> clone() const override
{
return std::make_unique<DerivedThing>(*this);
}
void do_thing() override
{
std::cout << "I'm doing something" << std::endl;
}
};
handle make_thing()
{
return handle(std::make_unique<DerivedThing>());
};
int main()
{
auto a = make_thing();
auto b = a;
a.do_thing();
b.do_thing();
return 0;
}
Now use your handle as if it had (moveable) value semantics
I am working on the following code
class base
{
private:
char* mycharpointer;
std::string mystring;
public:
base() : mycharpointer(NULL) {/*default constructor*/}
//Copy Constructor
base(const base& rhs){
if(mycharpointer != NULL) ---> Why is this condition true ?
{
mycharpointer = new char[ strlen(rhs.mycharpointer + 1)];
strcpy(this->mycharpointer,rhs.mycharpointer);
}
mystring = rhs.mystring;
}
base operator=(base& b)
{
if(this == &b)
return *this;
base temp(b);
temp.swap(*this);
return *this;
}
//Swap operation
void swap(base& lhs) {
std::swap(lhs.mycharpointer,this->mycharpointer);
std::swap(lhs.mystring,this->mystring);
}
//Destructor
virtual ~base(){
if(mycharpointer)
delete[] mycharpointer;
}
};
class der : public base
{
public:
char* mycharpointer_der;
std::string mystring_der;
foo* f;
public:
der():mycharpointer_der(NULL)
{
}
der(const der& rhs) : base(rhs)
{
if(mycharpointer_der)
{
mycharpointer_der = new char[ strlen(rhs.mycharpointer_der + 1)];
strcpy(this->mycharpointer_der,rhs.mycharpointer_der);
}
mystring_der = rhs.mystring_der;
f = new foo(*rhs.f);
}
der& operator=(der& d)
{
if(this == &d) //Make sure its not the same class
return *this;
base::operator= (d);
der temp(d);
temp.swap(*this);
return *this;
}
//Swap operation
void swap(der& lhs) {
std::swap(lhs.mycharpointer_der,this->mycharpointer_der);
std::swap(lhs.mystring_der,this->mystring_der);
}
virtual ~der(){
if(mycharpointer_der) //Necessary check as to make sure you are not deleting a NULL address otherwise exception thrown.
delete[] mycharpointer_der;
}
};
int main()
{
der d;
d.mycharpointer_der = "Hello World";
d.mystring_der = "Hello String";
der b;
b = d;
}
Now in the above code the copy assignment operator of d is called. which in return calls the copy assignment operator of the base class. In the copy assignment operator of the base class the copy constructor of the base class is called. My question is why is the condition
if(mycharpointer != NULL)
in the base class turning out as true ? Even when I have explicitly assigned it a NULL in the initialization list of the base class.
That check is ridiculous. At the point of construction, when we get into the body, mycharpointer is default-initialized and will contain some garbage value which may be 0 but likely won't be.
That said, what happens if rhs.mycharpointer is NULL? Then the strlen call would fail. That's the charpointer whose value you need to be checking:
base(const base& rhs)
{
if (rhs.mycharpointer) {
mycharpointer = new char[ strlen(rhs.mycharpointer) + 1 ];
// outside the parens ^^^^
strcpy(this->mycharpointer,rhs.mycharpointer);
}
else {
mycharpointer = NULL;
}
mystring = rhs.mystring;
}
Or since you're already using string, we could keep using string for mycharpointer too. That has the added benefit of us not even having to write the copy constructor which, as you can see, can be error prone:
base(const base& ) = default;
C++ compiler only make sure the global variable and static variables will be initialized, so In this case, the mycharpointer may actually points to some useless garbage(dangling pointer)
base(const base& rhs){
if(mycharpointer != NULL) ---> Why is this condition true ?
{
mycharpointer = new char[ strlen(rhs.mycharpointer + 1)];
strcpy(this->mycharpointer,rhs.mycharpointer);
}
mystring = rhs.mystring;
}
as mycharpointer actually point to the data allocated on the heap, so if you want to rellocate it, you need to release existing data first.
something like:
if ( mycharpointer) {
delete [] mycharpointer;
}
Apparently you're expecting the default constructor to run before the copy constructor does.
But it won't.
Due to this bug in Visual Studio 2013, I need to provide my own move constructor and move assignment for a derived class. However, I don't know how to call the appropriate move functions for the base class.
Here's the code:
#include <utility>
// Base class; movable, non-copyable
class shader
{
public:
virtual ~shader()
{
if (id_ != INVALID_SHADER_ID)
{
// Clean up
}
}
// Move assignment
shader& operator=(shader&& other)
{
// Brett Hale's comment below pointed out a resource leak here.
// Original:
// id_ = other.id_;
// other.id_ = INVALID_SHADER_ID;
// Fixed:
std::swap( id_, other.id_ );
return *this;
}
// Move constructor
shader(shader&& other)
{
*this = std::move(other);
}
protected:
// Construct an invalid shader.
shader()
: id_{INVALID_SHADER_ID}
{}
// Construct a valid shader
shader( const char* path )
{
id_ = 1;
}
private:
// shader is non-copyable
shader(const shader&) = delete;
shader& operator=(const shader&) = delete;
static const int INVALID_SHADER_ID = 0;
int id_;
// ...other member variables.
};
// Derived class
class vertex_shader final : public shader
{
public:
// Construct an invalid vertex shader.
vertex_shader()
: shader{}
{}
vertex_shader( const char* path )
: shader{path}
{}
// The following line works in g++, but not Visual Studio 2013 (see link at top)...
//vertex_shader& operator=(vertex_shader&&) = default;
// ... so I have to write my own.
vertex_shader& operator=(vertex_shader&&)
{
// What goes here?
return *this;
}
vertex_shader(vertex_shader&& other )
{
*this = std::move(other);
}
private:
// vertex_shader is non-copyable
vertex_shader(const vertex_shader&) = delete;
vertex_shader& operator=(const vertex_shader&) = delete;
};
int main(int argc, char* argv[])
{
vertex_shader v;
// later on
v = vertex_shader{ "vertex_shader.glsl" };
return 0;
}
What should the move assignment function in the derived class look like?
You just need to call the base class move assignment operator:
vertex_shader& operator=(vertex_shader&& rhs)
{
shader::operator=(std::move(rhs));
return *this;
}