I am writing a template function which accepts a custom class (that can be any class or primitive type) as a template argument, then reads some data (of that type) from an input stream, and then stores it an unordered map similar to this one:
std::unordered_map<CustomClass, std::vector<CustomClass>> map;
I have implemented a custom class to test the behavior. I have overloaded the std::hash so that this class can be stored in an unordered map as a key and overloaded all operators and constructors such that whenever they are called, I get a message in the console (example, when a copy constructor is called, I get a message "copy constructor [..data...]")
EDIT: As requested in the comments, here is the custom class definition and implementation (please note: the class here is only a placeholder so we can discuss the general idea behind this question. I am well aware that it is dumb and should not be implemented like this. The code for operators >> and << is not here, to avoid clutter)
class CustomClass {
public:
CustomClass(int a=0) {
std::cout << "default constructor" << std::endl;
m_data = a;
}
CustomClass(const CustomClass& other) {
std::cout << "copy constructor " ;//<< std::endl;
m_data = other.m_data;
std::cout << "[" << m_data << "]" << std::endl;
}
CustomClass(CustomClass&& other) {
std::cout << "move cosntructor" << std::endl;
m_data = other.m_data;
}
CustomClass& operator=(const CustomClass& other) {
std::cout << "copy assignment operator" << std::endl;
if(this != &other){
m_data = other.m_data;
}
return *this;
}
CustomClass& operator=(CustomClass&& other) {
std::cout << "move assignment operator" << std::endl;
if(this != &other){
m_data = other.m_data;
}
return *this;
}
~CustomClass() {
std::cout << "destructor" << std::endl;
}
int m_data;
};
Now my question is this: Is it possible to read data from the input stream and construct it inplace where it is needed without a copy constructor call?
Example of some code:
CustomClass x1; // default constructor call
CustomClass x2; // default constructor call
std::cout << "----" << std::endl;
std::cin >> x1 >> x2; // my input
std::cout << "----" << std::endl;
map[x1].emplace_back(x2); // 2 copy constructor calls
std::cout << "----" << std::endl;
std::cout << map[x1][0] << std::endl; // operator== call
std::cout << "----" << std::endl;
And here is an example output from that code:
default constructor
default constructor
----
[1]
[2]
----
copy constructor [1]
copy constructor [2]
----
operator ==
[2]
----
destructor
destructor
destructor
destructor
I would like to have it so that every object of this class is constructed only once.
Is it possible to avoid these copy constructors? If not both, then at least the one that is called during the emplace_back() call? Is it possible to construct the object in the vector exactly where it needs to be in memory but that this sort of call works for every type?
If I need to further elaborate on my question please tell me in the comments, I will be happy to do so
So you have an std::vector and you want to put an element there avoiding unnecessary copying. Assuming that move constructor for your class is cheap, the first option is to define a non-trivial constructor, read the parameters from stream and then emplace_back a newly created object:
using CustomClass = std::vector<int>;
std::vector<CustomClass> v;
size_t size;
int value;
std::cin >> size >> value;
v.emplace_back(size, value);
Here I defined the CustomClass as a vector of integers, and it has a constructor that takes 2 parameters: size and the value. For sure it is cheaper to read there two integers and create the instance of CustomClass only once and using the emplace_back for this purpose, rather than to create the instance and copy it using push_back:
using CustomClass = std::vector<int>;
std::vector<CustomClass> v;
size_t size;
int value;
std::cin >> size >> value;
CustomClass instance(size, value);
v.push_back(instance);
This however doesn't give you much benefits to compare with pushing back the r-value:
using CustomClass = std::vector<int>;
std::vector<CustomClass> v;
size_t size;
int value;
std::cin >> size >> value;
v.push_back(CustomClass(size, value));
Anyway, you need to keep in mind that both push_back and emplace_back may require reallocation of the elements, and that may be inefficient, especially if your CustomClass has no no-throwing move constructor.
Another problem could be if your class doesn't have a reasonable constructor (or the size of the values you need to pass to the constructor are almost the size of the object). In this case I'm offering you the solution to resize() and read to the back()
If the reallocation is something that you are not afraid of (for example you know the number of elements ahead of time and reserve the buffer), you can do the following:
std::vector<CustomClass> v;
v.resize(v.size() + 1);
std::cin >> v.back();
In this case you create a default value once and then read the contents.
Another solution could be to pass the std::istream to the constructor of CustomClass:
class CustomClass {
public:
CustomClass(std::istream&);
};
std::vector<CustomClass> v;
v.emplace_back(cin);
Update:
Assuming that you know nothing about the actual type of the CustomClass, the most generic (not fully generic, as it still requires default constructor to be able to be pushed with resize()) is to use resize()/back() idiom.
This is how you do it (avoids any unnecessary ctor calls, including a default one):
#include <vector>
#include <unordered_map>
#include <cstdio>
#include <iostream>
using namespace std;
//--------------------------------------------------------------------------
template <class F> struct inplacer
{
F f;
operator invoke_result_t<F&>() { return f(); }
};
template <class F> inplacer(F) -> inplacer<F>;
//--------------------------------------------------------------------------
struct S
{
S(istream&) { printf("istream ctor\n" ); }
S() { printf("ctor\n" ); }
~S() { printf("dtor\n" ); }
S(S const&) { printf("cctor\n"); }
S(S&&) { printf("mctor\n"); }
S& operator=(S const&) { printf("cop=\n"); return *this; }
S& operator=(S&&) { printf("mop=\n"); return *this; }
friend bool operator==(S const& l, S const& r) { return &l == &r; } //!! naturally, this needs proper implementation
};
template<> struct std::hash<S>
{
size_t operator()(S const&) const noexcept { return 0; } //!! naturally, this needs proper implementation
};
//--------------------------------------------------------------------------
template<class R> struct read_impl; // "enables" partial specialization
template<class R> R read(istream& is)
{
return read_impl<R>::call(is);
}
template<> struct read_impl<S>
{
static auto call(istream& is) { return S(is); }
};
template<class T> struct read_impl<vector<T>>
{
static auto call(istream& is)
{
vector<T> r; r.reserve(2); //!! naturally you'd read smth like length from 'is'
for(int i = 0; i < 2; ++i)
r.emplace_back(inplacer{[&]{ return read<T>(is); }});
return r;
}
};
template<class K, class V> struct read_impl<unordered_map<K, V>>
{
static auto call(istream& is)
{
unordered_map<K, V> r;
r.emplace( inplacer{[&]{ return read<K>(is); }}, inplacer{[&]{ return read<V>(is); }} );
return r;
}
};
//--------------------------------------------------------------------------
auto m = read<unordered_map<S, vector<S>>>(cin);
As you can see in the output -- you end up with 3 "istream ctor" calls and 3 "dtor" calls.
As for iostreams -- stay away from them if you care about performance, clarity, etc... The most ridiculous library ever.
P.S. "Partial specialization for function templates" trick is stolen from here.
Related
Implementing a reset() method, which uses some of the members from this to construct a new object and then move-assign that object to *this.
Questions:
Does this cause any problems? UB or otherwise? (seems fine to me?)
Is there a more idiomatic way?
Destructor and move-assignment operator only implemented to prove what is happening/ The real class has neither. "Rule of 5" not followed, as not needed here.
#include <algorithm>
#include <cstddef>
#include <iostream>
#include <numeric>
#include <ostream>
#include <random>
#include <vector>
struct Thing { // NOLINT Rule of 5 not followed, because debug only
public:
std::size_t size;
std::vector<int> v;
explicit Thing(std::size_t size_) : size(size_), v(size_) {
std::cerr << "Thing constructor\n";
std::iota(v.begin(), v.end(), 1);
}
~Thing() { std::cerr << "Thing destructor\n"; } // purely for debugging
Thing& operator=(Thing&& other) noexcept { // purely for debugging
std::cerr << "Thing Move Assignment operator\n";
size = other.size;
v = std::move(other.v);
return *this;
}
void shuffle() {
std::shuffle(v.begin(), v.end(), std::mt19937{1}); // NOLINT fixed seed
}
void reset() {
// move assignment operator from a newly constructed object. Constructor uses SOME of the
// member variables of *this
*this = Thing(size);
}
friend std::ostream& operator<<(std::ostream& os, const Thing& t) {
os << "[";
const char* delim = "";
for (const auto& e: t.v) {
os << delim << e;
delim = ",";
}
return os << "]";
}
};
int main() {
std::cerr << "Before inital construction\n";
auto t = Thing(10);
std::cout << t << "\n";
t.shuffle(); // somehow modify the object
std::cerr << "Before reset\n";
std::cout << t << "\n";
t.reset(); // reset using
std::cerr << "after reset\n";
std::cout << t << "\n";
}
Output:
Before inital construction
Thing constructor
[1,2,3,4,5,6,7,8,9,10]
Before reset
[10,1,3,6,8,5,7,4,2,9]
Thing constructor
Thing Move Assignment operator
Thing destructor
after reset
[1,2,3,4,5,6,7,8,9,10]
Thing destructor
Does this cause any problems? UB or otherwise? (seems fine to me?)
As long as the move assignment and the constructor are implemented in such a way that it does what you want, then I don't see a problem.
Is there a more idiomatic way?
I would invert the direction of re-use.
explicit Thing(std::size_t size_) : size(size_), v(size_) {
reset();
}
void reset() {
v.resize(size_);
std::iota(v.begin(), v.end(), 1);
}
If size is supposed to always match the size of the vector, then I would recommend removing the member since the size is already stored inside the vector. This has a caveat that in such case reset won't be able to restore a moved-from thing to its earlier size. But that's typically reasonable limitation.
Is there a way where I could move the object GuitarSpec that is created in main instead of it being copied?
So here is the following example:-
There is an Inventory class that has a list of guitars, and to add a guitar, there is a function called addGuitar that takes string, double and GuitarSpec object as an argument.
Inventory
class Inventory {
private:
list<Guitar> inventory;
public:
void addGuitar(const string &, double, const GuitarSpec &spec);
addGuitar function
void Inventory::addGuitar(const string &serialNumber, double price,
const GuitarSpec &spec) {
inventory.emplace_back(serialNumber, price, spec);
}
Guitar Constructor
Guitar::Guitar(const string& serialNumber, double price, const GuitarSpec &spec)
: serialNumber{serialNumber}, price{price}, spec(spec) {
cout << "Guitar Constructor" << endl;
}
Main function:-
Inventory inventory;
inventory.addGuitar(
"1001", 200,
GuitarSpec(toString(FEDER), "starocaster", toString(ELECTRIC),
toString(Wood::SIKTA), toString(Wood::SIKTA)));
Is there a way to move that GuitarSpec object instead of taking a copy of it, or any other better solution?
When you consider moving only one parameter, you might get away with declaring function overloads, one of which would be moving from a temporary. Or you have design where oly temporaries are used, then why don't you follow an "emplace" strategy instead and create new object on-site?
But with two or more parameters moved the number of required overloads would be four, eight and so on. That's not good, in that case perfect forward might be more useful. An example of forwarding single parameter (of type Spec) in C++11 style:
#include <iostream>
#include <utility>
struct Data {
Data(const Data&) { std::cout << "Data copied\n"; }
Data() { std::cout << "Data created\n"; }
};
struct Spec {
Data *ptr;
Spec() : ptr(new Data()) {};
Spec(const Spec& other) : ptr(new Data{*other.ptr}) {};
Spec(Spec && other) : ptr(other.ptr) {
other.ptr = nullptr;
std::cout << "Data moved\n";
}
Spec& operator=(const Spec& other) { ptr = new Data{*other.ptr};
std::cout << "Data copied\n";
return *this; }
Spec& operator=(Spec&& other) { ptr = other.ptr; other.ptr = nullptr;
std::cout << "Data moved\n"; return *this;
}
~Spec() { delete ptr; }
};
struct foo {
Spec d;
template < typename T, std::enable_if_t<std::is_convertible<T, Spec>::value> * = nullptr>
foo(T&& v) : d(std::forward<T>(v)) { }
template <typename T>
auto set_spec(T&& v) -> decltype(v = std::forward<Spec>(v), void())
{ d = std::forward<T>(v); }
};
int main()
{
std::cout << "Move\n";
foo a {Spec()};
a.set_spec(Spec());
std::cout << "Copy\n";
Spec s;
foo b {s};
a.set_spec(s);
}
You have to modify whole chain of responsibility to use that, starting with overloading Inventory's method:
void addGuitar(const string &serialNumber, double price, GuitarSpec&& spec) {
// move, do we want move string?
inventory.emplace_back(serialNumber, price, std::move(spec));
}
Or using perfect forwarding, this template can copy OR move, when appropriate (example without SFINAE):
template <class SN, class SP>
void addGuitar(SN&& serialNumber, double price, SP&& spec)
{
inventory.emplace_back(std::forward<std::string>(serialNumber),
price, std::forward<GuitarSpec>(spec));
}
Technically addGuitar might just be that if we don't want to bother about restricting interface by SFINAE, assuming we would always use it right and nothing wrong may happen (Murphy, put your hand down) if it's not a public interface. A bad assumption in large project with long life and multiple developers.
In my buggy class, I'm only exposing a constant version of MyStruct, experimenting with initializing a constant reference to the private member in an initializer list.
The program I'm debugging is functionally equivalent to the following:
#include <iostream>
#include <optional>
struct MyStruct {
int member = 1;
};
class MyType {
MyStruct struct_member_;
public:
MyType() : struct_member(struct_member_) {}
MyType& operator =(const MyType& other_side) {
struct_member_ = other_side.struct_member_;
return *this;
};
const MyStruct& struct_member;
void test() const {
std::cout << "Why isn't " << &struct_member << " the same as " << &struct_member_ << std::endl;
}
};
int main()
{
std::optional<MyType> my = MyType();
my.value().test();
std::optional<MyType> yours = MyType();
yours.value().test();
my = yours;
my.value().test();
my = MyType();
my.value().test();
return 0;
}
For this program, here's the output:
Why isn't 0x7ffeefbff890 the same as 0x7ffeefbff8a0
Why isn't 0x7ffeefbff868 the same as 0x7ffeefbff878
Why isn't 0x7ffeefbff890 the same as 0x7ffeefbff8a0
Why isn't 0x7ffeefbff890 the same as 0x7ffeefbff8a0
However, in the program I'm debugging, struct_member_ and struct_member are getting desynchronized (either the const reference struct_member is getting assigned to a different place in memory-- except it's const, or it's loosing track with an updated struct_member_-- except its memory address shouldn't change?) and I'm not sure which or why.
Any ideas on what could lead to this happening, or tips to make this pattern work with non-POD types? (I plan to be transitioning to method-based accessors anyway, since this experiment seems to be failing.)
Turns out optionals and copy constructors were key to all of this. The copy constructor was defaulting and I didn't realize it. Funny, because the compiler warned that I needed a non-default operator=, but didn't afford me the same warning for the copy constructor.
class MyType {
MyStruct struct_member_;
public:
MyType() : struct_member(struct_member_) {
std::cout << "constructor" << std::endl;
}
MyType(const MyType& other) : struct_member(struct_member_) {
std::cout << "copy constructor " << std::endl;
struct_member_ = other.struct_member_;
};
MyType& operator =(const MyType& other_side) {
std::cout << "assignment operator called" << std::endl;
struct_member_ = other_side.struct_member_;
return *this;
};
const MyStruct& struct_member;
void test() const {
std::cout << "Why isn't " << struct_member.member << ": " << &struct_member << " the same as " << &struct_member_ << std::endl;
}
};
Yields the correct output:
constructor
copy constructor
Why isn't 0x7ffeefbff8a0 the same as 0x7ffeefbff8a0
constructor
copy constructor
Why isn't 0x7ffeefbff878 the same as 0x7ffeefbff878
assignment operator called
Why isn't 0x7ffeefbff8a0 the same as 0x7ffeefbff8a0
constructor
assignment operator called
Why isn't 0x7ffeefbff8a0 the same as 0x7ffeefbff8a0
Altogether, it'd be less hassle just to expose getters as methods.
Either delete the copy constructor (because the default behavior binds the reference to the "wrong" thing in this case):
MyType(MyType const&) = delete;
Or provide a copy constructor that does the right thing, by binding the public const accessor to the self-same object:
MyType(MyType const& other)
: struct_member_{other.struct_member_}
, struct_member(struct_member_) {}
I am starting with C++ environment, I hope I didn't mess up a lot with the concepts here.
I have one task where I need to create an object that has to be able to be copied in two ways, with a shallow copy and a deep copy.
The object has to allow two types of copies. Either the object is shallow copied or deep copy depending on the demands.
In the code below I create a simple example to explain the use case. There, I implement the object Object with a one-argument constructor and a deep copy constructor. Then at some point we use the functions get_shallow and get_deep.
Is there a way to tell the compiler which constructor to use when it copies Object in the scope of the functions? Sometimes I will need a function to return the shallow copy and other times a deep copy.
using namespace std;
class Object;
typedef std::shared_ptr<Object> objectPtr;
class Object{
private:
int *data;
public:
Object(int d);
Object(const Object &source);
~Object();
};
// One argument constructor
Object::Object(int d) {
data = new int;
*data = d;
}
//deep copy constructor
Object::Object(const Object &source) :Object(*source.data) {}
Object::~Object() {delete data;}
Object get_shallow(Object object) {
return object;
}
Object get_deep(Object object) {
return object;
}
int main(){
Object object1 {100};
get_deep(object1); //returns a deep copy of the object
get_shallow(object1); //returns a shallow copy of the object
return 0;
}
You can use a tag on the copy constructor to indicate it is making a shallow copy.
Note carefully that a shallow copy does not own the resources. So when the owner gets destructed, any shallow copy will have dangling pointers. That's a very fragile situation, and easily the source of bugs.
An alternative solution is to have a std::shared_ptr for the shared resources, and then those resources exist until all owners relinquish ownership (typically relinquishing ownership upon destruction, but could be that they change ownership over the lifecycle of the entity object).
Regardless, here's an example of shallow copy constructor.
#include <iostream>
using std::cout;
using std::ostream;
class Object {
int* data;
bool delete_data = true;
public:
enum Shallow_tag { shallow };
~Object();
Object(int d);
Object(Object const&); // DEEP copy.
Object(Object const&, Shallow_tag); // SHALLOW copy.
bool is_shallow() const { return !delete_data; }
auto get_data() const -> int* { return data; }
};
Object::~Object() { if (delete_data) delete data; }
// One argument constructor
Object::Object(int d) : data{new int(d)} { }
//deep copy constructor
Object::Object(Object const& other) : Object(*other.data) {}
// shallow copy
Object::Object(Object const& other, Shallow_tag) : data{other.data}, delete_data{false} {}
Object get_shallow(Object const& object) {
return Object(object, Object::shallow);
}
Object get_deep(Object object) {
return object;
}
ostream& operator<<(ostream& out, Object const& obj) {
out << (obj.is_shallow() ? "shallow" : "deep") << " ";
auto d = obj.get_data();
if (d) out << "data:" << *d;
else out << "data:(null)";
return out;
}
int main() {
auto object1 = Object{100};
auto obj2 = get_deep(object1); //returns a deep copy of the object
auto obj3 = get_shallow(object1); //returns a shallow copy of the object
cout << "obj2 is " << obj2 << "\n";
cout << "obj3 is " << obj3 << "\n";
}
UPDATE: using shared_ptr for the data.
Of course, an int as shared data is probably a bit silly. But for the purposes of an example it is illustrative of whatever the data payload type.
#include <iostream>
#include <memory>
using std::cout;
using std::make_shared;
using std::ostream;
using std::shared_ptr;
class Object {
shared_ptr<int> data;
public:
Object(int d);
auto get_data() const -> int* { return data.get(); }
};
Object::Object(int d) : data{make_shared<int>(d)} { }
auto operator<<(ostream& out, Object const& obj) -> ostream& {
auto d = obj.get_data();
if (d) out << "data:" << *d;
else out << "data:(null)";
return out;
}
Object get_copy(Object o) {
return o;
}
int main() {
auto object1 = Object{100};
auto obj2 = get_copy(object1);
auto obj3 = get_copy(object1);
cout << "obj2 is " << obj2 << "\n"; // 100
cout << "obj3 is " << obj3 << "\n"; // 100
*object1.get_data() = 5;
cout << "obj2 is " << obj2 << "\n"; // 5
cout << "obj3 is " << obj3 << "\n"; // 5
obj2 = Object{75};
cout << "obj2 is " << obj2 << "\n"; // 75
cout << "obj3 is " << obj3 << "\n"; // 5
}
I can't figure out how push_back(const value_type& val) exactly works, in docs it says about val that
val is Value to be copied (or moved) to the new element ...
How it can be copied when it takes val by reference ?
Will that copying ever call the copy constructor of val ?
and what's exactly happening here ?
#include <iostream>
#include <vector>
using namespace std;
struct x
{
x(int v = 0) : v(v) {}
int v;
};
vector<vector<x>> parts;
void fillParts()
{
vector<x> values = { x(1), x(2), x(3) };
parts.push_back(values);
}
int main()
{
fillParts();
parts[0][0].v = -123;
cout << parts[0][0].v; // -123
return 0;
}
this runs with no erros,
is parts[0] is a reference to local vector values or a copy ?
if it is a reference shouldn't it at least give some warnings saying that your accessing and modifying local objects of freed stack ?
How it can be copied when it takes val by reference?
Think of a copy constructor.
It takes parameter by reference, and it performs copying perfectly.
class Bar
{
public:
Bar(const Bar & rhs); // by reference, to copy.
};
Will that copying ever call the copy constructor of val ?
Copy operation uses copy constructor.
You can actually see if it's copied, or moved by providing user-defined constructors.
struct x
{
public:
x(const x & rhs)
{
// Some copy operation.
std::cout << "Copied" << std::endl;
}
x(x && rhs)
{
// Some move operation.
std::cout << "Moved" << std::endl;
}
};
You can try this
class A
{
public:
A() {}
A(const A&) { cout << "copy cons" << endl; }
A& operator= (A &&) { cout << "move" << endl; };
A& operator= (const A &) { cout << "copy" << endl; };
};
vector<A> parts;
void fillParts()
{
A a;
parts.push_back(a);
}
int main()
{
fillParts();
return 0;
}
I got copy cons called in both debug and release builds.