std::map with only move constructor available - c++

I have a class with private constructor (that my container class can access), deleted copy constructor, and default move constructor. How can I use it in a std::map?
class Item {
public:
Item(const Item&) = delete;
private:
friend class Storage;
Item(int value);
};
class Storage {
public:
void addItem(int key, int value) {
// what to put here?
}
private:
std::map<int, Item> items_;
};
Using emplace(key, Item(value)) doesn't work, because it tries to copy construct the item. Wrapping Item in std::move has the same effect. Using piecewise_construct doesn't work because the map (or pair) tries to use normal constructor, which is private.

I have a class with private constructor (that my container class can access), deleted copy constructor, and default move constructor.
Wrong, you do not have a defaulted move constructor. You don't get an implicit move constructor if you declare a copy constructor. You'll need to explicitly default the move constructor to get one:
class Item {
public:
Item(const Item&) = delete;
Item(Item&&) = default;
// Might be a good idea to declare the two assignment operators too
Item& operator=(const Item&) = delete;
Item& operator=(Item&&) = default;
private:
friend class Storage;
Item(int value);
};
Now you can use:
items_.emplace(key, Item(value));
for example to insert an entry.

Related

Copy Constructors, Assignment Operator C++

I am very new to OOP and am still trying to comprehend all the concepts of the constructors. I have a class with some data and I have to make a Copy Constructor and Assignment Operator, however, since this is the first time I am doing something like this, I am not sure if what I have written makes sense. So, I am asking if what I have written are valid Copy Constructor and Assignment Operator. The class is saved in a file called BKS.h Thank you!
Here is the class :
#include <iostream>
#include <vector>
#include <cassert>
#include <algorithm>
using namespace std;
template <class T>
class BKS final
{
public:
struct Item
{
T identifier;
int weight;
int benefit;
};
BKS() {}
BKS(const BKS<T> &copy);
BKS(const vector<Item> &items) : itemlist_{items} {}
BKS(const vector<pair<int, int>> &weight_benefit_list);
BKS<T> &operator=(const BKS<T> &copy);
// some methods ....
private:
vector<Item> itemlist_;
vector<int> current_selection_;
int current_capacity_ {0};
int maximal_benefit_ {0};
};
Copy Constructor and Assigment Operator :
#include "bks.h"
template <class T>
BKS<T>::BKS(const BKS<T> &copy) // copy constructor
{
std::vector<Item> itemlist_ = copy.itemlist_;
std::vector<int> current_selection_ = copy.current_selection_;
int current_capacity_ = copy.current_capacity_;
int maximal_benefit_ = copy.maximal_benefit_;
}
template <class T>
BKS<T> &BKS<T>::operator=(const BKS<T> &copy)
{
if (&copy != this)
{ // check for self-assignment
this->itemlist_ = copy.itemlist_;
this->current_selection_ = copy.current_selection_;
this->current_capacity_ = copy.current_capacity_;
this->maximal_benefit_ = copy.maximal_benefit_;
}
return *this;
}
Also any general recommendations concerning constructors are welcome :)
If your instructor insists you must declare special members, but gives no guidance on how, then the best way is:
template <class T>
class BKS final
{
public:
~BKS() = default;
BKS(const BKS &) = default;
BKS& operator=(const BKS &) = default;
BKS(BKS &&) = default;
BKS& operator=(BKS &&) = default;
/* other members... */
};
If your instructor doesn't require you to declare them, but only requires they exist, the best way is
template <class T>
class BKS final
{
public:
/* other members... */
};
When you create a new class without declaring a copy constructor, a copy assignment operator and a destructor, compilers will declare their own versions of a copy constructor, a copy assignment operator and a destructor. Furthermore, if you don't declare your constructor, the compilers will implicitly declare one for you.
All these default compiler generated functions are all public and inline. Notice that the implictly-declared destructor is non-virtual.
So what will the default constructor, default copy constructor, default copy assignment operator and default destructor do?
Default constructor (either implicitly-declared or user-defined): calls the default constructors of the bases and of the non-static members of the class;
Default copy constructor(implicitly-declared) and default copy assignment operator(implicitly-declared): copy each non-static data member of the source object to the target object;
Default destructor(either implicitly-declared or user-defined): calls the destructors of the base class and members of the derived class.
Here in your cases, your non-static data members will be copied by default copy constructor and default copy assignment operator. There's no need defining your own copy constructor and copy assignment operator unless you want to add specific behaviors for your copy constructor and copy assignment operator.
References:
https://en.cppreference.com/w/cpp/language/default_constructor
https://www.ibm.com/support/knowledgecenter/SSLTBW_2.3.0/com.ibm.zos.v2r3.cbclx01/cplr380.htm
Book: "Effective C++" by Scott Meyers, Chapter 2

Are there possible troubles to use default copy constructor in clone idiom?

I have :
class myClass : public baseClass
{
public:
myClass(const unsigned short int dim_alphabet ,const string *alf ,const map<vector<string>, int> &samples );
myClass(const approximateOracle& apOracle); //copy constructor
virtual ~myClass();
virtual myClass* clone() const;
virtual bool myMethod(vector<SYMBOL> str);
virtual bool myMethod2(dfa* dfahp , vector<SYMBOL>* witness_results=NULL);
private:
void encode_data(vector< pair<vector<double> , labelType> > &mapped_samples , const map<vector<string>, int> &samples);
int length_longer_sentence;
vector<double> mean;
vector<double> standard_deviation; //data structure for save the standard_deviation of features
where implementation of clone() is:
myClass* myClass::clone() const
{
return(new myClass(*this)); //this code cause the call of copy constructor
}
I'm using the clone idiom.
I would delete the explicit definition of the copy constructor. I haven't pointers that require deep copy. Thus, with the default copy constructor provided from compiler (if I delete the mine) the automatic shallow copy of members of myClass should be ok.
But I have some doubt because of the presence of the clone idiom. Is there any contraindication about delete the explicit copy constructor?

Is default move constructor optimized away by compiler?

I have an std::multimap of the following type:
typedef std::multimap<std::pair<bool,uint32_t>, FooObject>
The FooObject has default move copy and assign constructors declared:
FooObject(FooObject&& v) = default;
FooObject& operator=(FooObject&& other)=default;
The copy/assign constructors are private to disable implicit copy.
So I should be able to emplace a pair into the map like this:
mymap.emplace(std::make_pair(false,32),FooObject());
This throws a list of errors with the one at the end:
error C2660: 'std::pair::pair': function does not take
2 arguments
If I declare move copy assign constructors without "default"
then it compiles ok.
FooObject(FooObject&& v){}
FooObject& operator=(FooObject&& other){}
Why is that? Does the compiler optimize away these constructors when marked with "default" keyword? I am using MSVC140
UPDATE:
Based on the comments below I found the reason - FooObject has a non-copiable member instance.
Here is the FooObject:
#define NO_COPY_ASSIGN(TypeName) \
TypeName (const TypeName &); \
void operator= (const TypeName &);
class FooObject
{
private:
NO_COPY_ASSIGN(FooObject)
public:
struct FooStruct
{
FooBuffer frameBuffer; //<--Here it is
}fooStruct;
FooObject(){}
/** Move constructor to allow insert into vector without copy */
FooObject(FooObject&& v) = default;
FooObject& operator=(FooObject&& other) = default;
};
*FooBuffer has also its copy/assign private.But I still don't get why replacing 'default' with {} fixes that.Please explain.
Your problem is that one of the member of FooObject is not move-able, which prevents the compiler from generating default move operations.
The {} versions of the move operations you implement yourself do no work (specifically: they don't actually do a move operation) on the members of FooObject and are thus legal.
The difference between
FooObject(FooObject&& v) = default;
and
FooObject(FooObject&& v){}
Is that the former will emit a constructor that moves each member from v while the latter default constructs each member and does nothing with v.
Since FooBuffer is not movable that means that the compiler will delete FooObject(FooObject&& v) = default; as it would be ill-formed.
With FooObject(FooObject&& v){} you do not have that problem as you never try to move the members of v. Since there is no member initialization list the compiler will add one for you that just default constructs the members.
You can see this behavior more explicitly with this:
struct Moveable
{
Moveable() = default;
Moveable(Moveable&&) { std::cout << "in Moveable(Moveable&&)\n"; }
};
struct Foo
{
Foo() = default;
Foo(Foo&&) = default;
Moveable m;
};
struct Bar
{
Bar() = default;
Bar(Bar&&){}
Moveable m;
};
int main()
{
Foo f;
Bar b;
std::cout << "test_f\n";
Foo test_f(std::move(f));
std::cout << "test_b\n";
Bar test_b(std::move(b));
}
which outputs
test_f
in Moveable(Moveable&&)
test_b
Live Example
Showing that nothing is actually moved in Bar's move constructor.

Overloading copy constructor with delete and then calling the default constructor of a subclass in C++

I am trying to disable or rather delete the copy constructor of the parent class Card with the line Card(const Card&) = delete;
When I call Quartz* qu = new Quartz(); in the main i get the error that the default constructor is deleted? I find this confusing since I did not think I was defining a default constructor in Card but rather an overload of the copy constructor. Any explanations or workarounds for this much appreciated.
class Card {
public:
Card(const Card&) = delete;
};
class Quartz : public Card {
public:
Quartz() = default;
};
int main() {
Quartz* qu = new Quartz();
}
Default constructor is only implicitly defined if the class has no other constructors. Since you defined a copy constructor, you now need to explicitly define default one, too.

How to ensure the move constructor is used

The code below gives the error:
use of deleted function ‘constexpr B::B(const B&)’
now, I know this happens because the copy constructor is (intentionally) implicitly deleted by specifying a move constructor, and that copying the vector causes the calls to the (deleted) copy constructor. I think I also understand why the vector's copy constructor and assignment operator are used. I clearly want to use the move constructor and assignment operator though: move the object, so also move the vector it contains. So, how do I get my move constructor/assignment operator to use the vector's move constructor/assignment operator?
Here is the code:
#include <vector>
class B {
private:
/* something I don't want to copy */
public:
B() {};
B(B&& orig) {/* move contents */};
B& operator=(B&& rhs) {
/* move contents */
return *this;
};
};
class A {
private:
vector<B> vec;
public:
A() : vec() {};
A(A&& orig) : vec(orig.vec) {};
A& operator=(A&& rhs) {
vec = rhs.vec;
return *this;
};
};
Just call std::move on the vectors in the expression in which you want to move from them:
class A {
private:
vector<B> vec;
public:
A() : vec() {};
A(A&& orig) : vec(std::move(orig.vec)) {};
// ^^^^^^^^^
A& operator=(A&& rhs) {
vec = std::move(rhs.vec);
// ^^^^^^^^^
return *this;
};
};
Even though you take in rvalue references, rhs and orig are still lvalues in the function, so you need to call std::move on them.
To ensure that the "move" constructor and assignment operators are called, you need to provide an object of the correct value category. The value category is used to determine which operators and constructors could be used.
Use std::move to change the value category (from the lvalue in this case) to a xvalue (an rvalue, that can be moved from).
// ...
A(A&& orig) : vec(std::move(orig.vec)) {};
A& operator=(A&& rhs) {
vec = std::move(rhs.vec);
return *this;
};
The move does not copy or change the object in any way, it is simply a cast to an rvalue reference of the argument type - hence modifying the value category.
If all the members of your class are the objects of classes with correctly defined move constructor/assignment operator you should better use default move constructor/assignment operator for your class. This would be much easier and less error-prone and ensure the call of move constructor/assignment operator of class members.
In your particular example it would be:
class A
{
private:
vector<B> vec;
public:
A() : vec() {};
A(A&&) = default;
A& operator=(A&&) = default;
};