inserting object in a map without copying the object - c++

Is it possible to insert objects in a map, if the class of the object has disabled copy constructor and disabled copy operator? Is move semantics useful here?
#include <map>
class T {
public:
T(int v): x(v) {};
private:
T(const T &other); // disabled!
T &operator=(const T &other); // disabled!
int x;
};
int main() {
std::map<int, T> m;
m[42] = T(24); // compilation error here!
}
edit I was not completely clear. The object is huge, so I don't want to make unnecessary copies of it. But I can modify the code of the class (maybe I need to implement move semantics?) and not the user code (the main function in the example).

Use emplacement syntax:
m.emplace(std::piecewise_construct,
std::forward_as_tuple(42), std::forward_as_tuple(24));
// ^^ ^^
// int(42) T(24)
Or, in C++17, use try_emplace:
m.try_emplace(42, 24);

This might be what you are looking for:
class T {
public:
T(){};
T(int v): x(v) {};
T(const T &other) = delete;
T(T&& other) {x = other.x; std::cout << "move ctor\n";}
T &operator=(const T &other) = delete;
T& operator=(T&& other) {x = other.x; std::cout << "move assigment\n";}
private:
int x;
};
int main() {
std::map<int, T> m;
m.insert(std::make_pair(42, T(24)));
m[44] = T(25);
}

You might insert as pointer:
public:
T(int v) : x(v) {};
int getX(){ return this->x; }
private:
T(const T &other); // disabled!
T &operator=(const T &other); // disabled!
int x;
};
int main()
{
std::map<int, T*> m;
m[42] = new T(24); // no compilation error here!
std::cout << m[42]->getX() << std::endl; // prints out 24
return 0;
}

Related

Writing a copyable unique_ptr for copyable classes with PIMPL idiom

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 to swap two objects without copy assignment operator?

I have a class A where, the copy assignment operator is deleted. How should I swap two instances of A ?
I tried using std::swap but that did not work.
class A {
private:
int a;
public:
A& operator=(const A& other) = delete;
A(int _a = 0):a(_a){}
void showA() { std::cout << a << std::endl; }
};
int main()
{
A obj1(10);
A obj2(20);
obj1.showA();
obj2.showA();
//A temp;
//temp = obj1;
//obj1 = obj2;
//obj2 = temp;
obj1.showA();
obj2.showA();
}
I expect obj1 and obj2 to be swapped. Initially obj1.a is 10 and obj2.a is 20, I expect obj1.a to be 20 and obj2.ato be 10 when done.
As #Yksisarvinen indicated you need to have move constructor and move assignment defined in order to get std::move to work:
#include <iostream>
#include <utility>
class A {
private:
int a;
public:
A(int a_) : a(a_) {}
A(const A& other) = delete;
A& operator=(const A&) = delete;
A(A&& other) {
a = other.a;
}
A& operator=(A&& other) {
a = other.a;
return *this;
}
void showA() { std::cout << a << std::endl; }
};
int main(int argc, char* argv[]) {
A obj1(10);
A obj2(20);
obj1.showA();
obj2.showA();
std::swap(obj1, obj2);
std::cout << "swapped:" << std::endl;
obj1.showA();
obj2.showA();
return 0;
}

How can I fix this error in this case? "Invalid arguments ' Candidates are: void FreeMemory(std::vector<Element *,std::allocator<Element *>> &) '"?

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.

Design pattern for methods that return object and NRVO

I have class:
class A{
public:
A(int v){
this->v=new int;
*(this->v)=v;
}
~A(){
delete v;
}
A add(A &a, A &b){
A res(0);
*(res.v)=*(a.v)+*(b.v)+*v;
return res;
}
int get(){
return *v;
}
private:
A();
int* v;
void operator=(const A &other);
TreePointer(const A &other);
};
I want to use it as follows:
A finalRes=a.add(b,c).add(a,a);
It works perfectly, there is no any leaks memory.
But how to implement a similar behavior and usage, without using NRVO optimization? What standard design patterns exist for this purpose?
Avoid new, prefer std::unique_ptr instead.
In your case, in fact, you don't even need pointer:
class A{
public:
explicit A(int v) : v(v){}
~A() = default;
void operator=(const A &) = default;
A(const A &) = default;
A add(const A& a, const A& b) const { return A{v + a.v + b.v}; }
int get() const { return v; }
private:
int v;
};

Move constructor c++

What's the right way to do a move constructor ?
class A{
...some stuff...
private:
int i;
std::string str;
};
A::A(A &&a)
{
*this = std::move(a);
};
or
A::A(A &&a)
{
this->str = std::move(a.str);
};
In the second case, is it useful to std::move() the int value ?
It should be
A::A(A&& other)
: i{other.i},
str{std::move(other.str)} {
// nop
}
This is the default implementation for a move constructor.