I have been searching for a while but I couldn't find clear explanation for my doubts.
Mainly:
struct foo
{
foo(int n=0) : m_n(n) {}
int m_n;
};
std::vector<foo> vec;
vec.push_back(100);
vec.push_back(55);
vec.push_back(6);
std::cout << vec.data() << std::endl; //0x1aca010
std::cout << vec.capacity() << std::endl; //4
vec.push_back(6);
vec.push_back(6);
std::cout << vec.data() << std::endl; //0x1aca050 *
std::cout << vec.capacity(); //8
*As I understand a vector is an dynamic array which contains data in one continuous block of memory. When we resize it and there is out of space for more elements, new block of memory is being allocated and all elements are copied to that one. Does it work the same with respect to the move semantic in c++11? It's not a list so pointers can't be just "swaped".
Why do you think pointers can't just be "swapped"? Let me show you a possible implementation >o<
template <typename T>
class vector
{
private:
T *mem;
// ...
public:
// ...
vector(vector &&rhs)
: vector() // delegate constructor
{
rhs.swap(*this);
}
vector &operator =(vector &&rhs)
{
rhs.swap(*this);
rhs.clear();
rhs.shrink_to_fit();
return *this;
}
void swap(vector &obj)
{
using std::swap;
swap(mem, obj.mem);
// ...
}
// ...
};
However, if you want to use a different allocator from an original vector (i.e. to use the sixth constructor of this page), you should allocate new memory and copy data into it, not just swap pointers.
Related
During implementation of a code copying of map elements into a vector I found out that std::transform calls the copy ctor of my custom class multiple times despite of prior vector size reservation. So I compared different ways to do this, and saw that the best method is a simple for-loop. So my question is: are these algorithms really more expensive? If so what is the advantage of them? Or does it not matter for small number of elements? Here my test code:
class A
{
public:
A() {}
A(int ai) : i(ai) {}
A(A& a) : i(a.i) { std::cout << "copy ctor " << i << std::endl; }
A(const A& a) : i(a.i) { std::cout << "copy const ctor " << i << std::endl; }
A(A&& a) : i(std::move(a.i)) { std::cout << "move ctor " << i << std::endl; }
// I removed overloaded operators because they are not called here...
private:
int i;
};
std::map<int, A> m;
m.insert(std::make_pair(0, A(7)));
m.insert(std::make_pair(1, A(3)));
m.insert(std::make_pair(2, A(1)));
std::vector<A> vec;
vec.reserve(m.size());
std::transform(m.begin(), m.end(), std::back_inserter(vec), [](const std::pair<int, A> & p) { return p.second; }); // 3 calls for each ctor
//... clean up and reserve vec
std::for_each(m.begin(), m.end(), [&vec](const std::pair<int, A> & p) { vec.push_back(p.second); }); // 2 calls for each ctor
//... clean up and reserve vec
for (const auto & p : m) // 1 call for each ctor
{
vec.emplace_back(p.second);
}
The element type in a std::map is std::pair<const Key, Value>.
In your example use use std::pair<int, A> without const, so you need to copy the pair. This adds a copy in the first two solutions. If you change it to std::pair<const int, A> you can see 2 constructor calls in the first iteration and only one in the second (on par with your for loop).
For the first iteration you now have 1 copy and one move. This is because your lambda needs to copy the A then back_inserter move constructs it into the vector. Normally I wouldn't worry about an extra move since they are supposed to be cheap.
However, you can get rid of it. We can force the lamba to not copy the A instance, by ,for example, specifying the return type to be a reference. So now the back_inserter will have to copy when it inserts, but that's it.
This version of your code does one copy per element for each solution:
std::map<int, A> m; m.insert(std::make_pair(0, A(7))); m.insert(std::make_pair(1, A(3))); m.insert(std::make_pair(2, A(1))); std::vector<A> vec;
std::cout << "Transform" << std::endl;
vec.reserve(m.size());
std::transform(m.begin(), m.end(), std::back_inserter(vec),
// changed the key type and return type.
[](const std::pair<const int, A> & p)->const A& { return p.second; });
std::cout << "for_each" << std::endl;
vec.resize(0);
vec.reserve(m.size());
std::for_each(m.begin(), m.end(),
// changed the key type.
[&vec](const std::pair<const int, A> & p) { vec.push_back(p.second); });
std::cout << "START\n";
vec.resize(0);
vec.reserve(m.size());
for (const auto & p : m) {
vec.emplace_back(p.second);
}
#include <memory> // for std::unique_ptr and std::make_unique
#include <iostream>
class Fraction
{
private:
int m_numerator;
int m_denominator;
public:
Fraction(int numerator, int denominator) :
m_numerator{ numerator }, m_denominator{ denominator }
{
}
friend std::ostream& operator<<(std::ostream& out, const Fraction &f1)
{
out << f1.m_numerator << "/" << f1.m_denominator;
return out;
}
friend operator=(const Fraction &f1,const int numerator,const int denominator){
f1.m_numerator=numerator;
f1.m_denominator=denominator;
}
};
int main()
{
// Create a single dynamically allocated Fraction with numerator 3 and denominator 5
std::unique_ptr<Fraction> f1{ std::make_unique<Fraction>(3, 5) };
std::cout << *f1 << '\n';
// Create a dynamically allocated array of Fractions of length 4
// We can also use automatic type deduction to good effect here
auto f2{ std::make_unique<Fraction[]>(4) };
f2[0]=(3,5);
f2[1]=(67,82,5,543345);
std::cout << f2[0] << '\n';
std::cout << f2[1] << '\n';
return 0;
}
First, operator= can be implemented only as member function, not free function. So your approach is just wrong. Second, overloaded operator= can accept only one parameter. The closest thing you want, can be achived by passing initializer_list as this parameter:
Fraction& operator=(std::initializer_list<int> il){
// some code validating size of il here
this->m_numerator=*il.begin();
this->m_denominator = *(il.begin()+1);
return *this;
}
the use looks like:
f2[0]={3,5};
f2[1]={67,84};
Full demo
maybe I get something wrong with shared_pointers or there is some basic shortcoming of mine but I couldn't get this right. So I want to read in some data from a file. There are position and momentum data on each line of the data file and the first line stores the number of data points.
I need to read this in to my data structure and for some reason my graph would not fill, although the data reads in correctly.
const int dim = 3; // dimension of problem
template <typename T, typename G>
// T is the type of the inputted locations and G is the type of the
// distance between them
// for example: int point with float/double distance
struct Node{
std::pair< std::array<T, dim>,std::pair< std::array<T, dim>, G > > pos; // position
std::pair< std::array<T, dim>,std::pair< std::array<T, dim>, G > > mom; // momentum
// a pair indexed by a position in space and has a pair of position
// and the distance between these points
};
template <typename T, typename G>
struct Graph{
int numOfNodes;
std::vector< Node<T,G> > nodes;
};
This is the data structure and here's my read function (std::cout-s are only for testing):
template <typename T, typename G>
std::istream& operator>>(std::istream& is, std::shared_ptr< Graph<T,G> >& graph){
is >> graph->numOfNodes; // there's the number of nodes on the first line of the data file
std::cout << graph->numOfNodes << "\n";
for(int k=0; k<graph->numOfNodes; k++){
Node<T,G> temp;
for(auto i : temp.pos.first){
is >> i;
std::cout << i << "\t";
}
std::cout << "\t";
for(auto i : temp.mom.first){
is >> i;
std::cout << i << "\t";
}
std::cout << "\n";
graph->nodes.push_back(temp);
}
return is;
}
I have an output function as well. So if I output the graph which I intended to fill during read-in is zeroed out. Number of nodes os correct however positions and momente are all zeroed out. What did I do wrong? Thanks in advance.
for(auto i : temp.pos.first){
is >> i;
std::cout << i << "\t";
}
Think of this as similar to a function. If you have something like:
void doX(int i) { i = 42; }
int main() {
int j=5;
doX(j);
return j;
}
Running this code, you'll see the program returns the value 5. This is because the function doX takes i by value; it basically takes a copy of the variable.
If you replace doX's signature with
void doX(int &i)
and run the code, you'll see it returns 42. This is because the function is now taking the argument by reference, and so can modify it.
Your loops will behave similarly. As you have it now, they take a copy of the values in the arrays in turn, but are not by reference.
As with the function, you can change your loops to look like
for(auto &i : temp.pos.first){
is >> i;
std::cout << i << "\t";
}
This should then let you change the values stored in the arrays.
#include <iostream>
class A{
public:
A(){std::cout << "basic constructor called \n";};
A(const A& other) {
val = other.x
std::cout << "copy constructor is called \n";
}
A& operator=(const A& other){
val = other.x
std::cout << "\n\nassignment operator " << other.val << "\n\n";
}
~A(){
std::cout << "destructor of value " << val <<" called !!\n";
}
A(int x){
val = x;
std::cout << " A("<<x<<") constructor called \n";
}
int get_val(){
return val;
}
private:
int val;
};
int main(){
// non pointer way
A a;
a = A(1);
std::cout << a.get_val() << std::endl;
a = A(2);
std::cout << a.get_val() << std::endl;
// pointer way
A* ap;
ap = new A(13);
std::cout << ap->get_val() << std::endl;
delete ap;
ap = new A(232);
std::cout << ap->get_val() << std::endl;
delete ap;
return 0;
}
I initially create an object out of default constructor and then assign tmp r-value objects A(x) to a. This ends up calling assignment operator. So in this approach there are 3 steps involved
(non-pointer way)
1) constructor
2) assignment operator
3) destructor
Where as when I use pointer it only requires two step
(pointer way)
1) constructor
2) destructor
My question is should I use non-pointer way to create new classes or should I use pointer way. Because I have been said that I should avoid pointers (I know I could also use shared_ptr here).
Rule of thumb: Prefer to create objects on the stack. There is less work for memory management when you create objects on the stack. It is also more efficient.
When do you have to create objects on the heap?
Here are some situations that need it:
You need to create an array of objects where the size of the array is known only at run time.
You need an object to live beyond the function in which it was constructed.
You need to store and/or pass around a pointer to a base class type but the pointer points to a derived class object. In this case, the derived class object, most likely, will need to be created using heap memory.
Assume you have many elements, and you need to keep track of the equivalence relations between them. If element A is equivalent to element B, it is equivalent to all the other elements B is equivalent to.
I am looking for an efficient data structure to encode this information. It should be possible to dynamically add new elements through an equivalence with an existing element, and from that information it should be possible to efficiently compute all the elements the new element is equivalent to.
For example, consider the following equivalence sets of the elements [0,1,2,3,4]:
0 = 1 = 2
3 = 4
where the equality sign denotes equivalence. Now we add a new element 5
0 = 1 = 2
3 = 4
5
and enforcing the equivalence 5=3, the data structure becomes
0 = 1 = 2
3 = 4 = 5
From this, one should be able to iterate efficiently through the equivalence set for any element. For 5, this set would be [3,4,5].
Boost already provides a convenient data structure called disjoint_sets that seems to meet most of my requirements. Consider this simple program that illustates how to implement the above example:
#include <cstdio>
#include <vector>
#include <boost/pending/disjoint_sets.hpp>
#include <boost/unordered/unordered_set.hpp>
/*
Equivalence relations
0 = 1 = 2
3 = 4
*/
int main(int , char* [])
{
typedef std::vector<int> VecInt;
typedef boost::unordered_set<int> SetInt;
VecInt rank (100);
VecInt parent (100);
boost::disjoint_sets<int*,int*> ds(&rank[0], &parent[0]);
SetInt elements;
for (int i=0; i<5; ++i) {
ds.make_set(i);
elements.insert(i);
}
ds.union_set(0,1);
ds.union_set(1,2);
ds.union_set(3,4);
printf("Number of sets:\n\t%d\n", (int)ds.count_sets(elements.begin(), elements.end()));
// normalize set so that parent is always the smallest number
ds.normalize_sets(elements.begin(), elements.end());
for (SetInt::const_iterator i = elements.begin(); i != elements.end(); ++i) {
printf("%d %d\n", *i, ds.find_set(*i));
}
return 0;
}
As seen above one can efficiently add elements, and dynamically expand the disjoint sets. How can one efficiently iterate over the elements of a single disjoint set, without having to iterate over all the elements?
Most probably you can't do that, disjoint_sets doesn't support iteration over one set only. The underlying data structure and algorithms wouldn't be able to do it efficiently anyway, i.e. even if there was support built in to disjoint_sets for iteration over one set only, that would be just as slow as iterating over all sets, and filtering out wrong sets.
Either I am missing something, you forgot to mention something, or maybe you were overthinking this ;)
Happily, equivalence is not equality. For A & B to be equivalent; they only need to share an attribute with the same value. this could be a scalar or even a vector. Anyway, I think your posted requirements can be achieved just using std::multiset and it's std::multiset::equal_range() member function.
//////////////////////////////////////
class E
{
//could be a GUID or something instead but the time complexity of
//std::multiset::equal_range with a simple int comparison should be logarithmic
static size_t _faucet;
public:
struct LessThan
{
bool operator()(const E* l, const E* r) const { return (l->eqValue() < r->eqValue()); }
};
using EL=std::vector<const E*>;
using ES=std::multiset<const E*, E::LessThan>;
using ER=std::pair<ES::iterator, ES::iterator>;
static size_t NewValue() { return ++_faucet; }
~E() { eqRemove(); }
E(size_t val) : _eqValue(val) {}
E(std::string name) : Name(name), _eqValue(NewValue()) { E::Elementals.insert(this); }
//not rly a great idea to use operator=() for this. demo only..
const E& operator=(const class E& other) { eqValue(other); return *this; }
//overriddable default equivalence interface
virtual size_t eqValue() const { return _eqValue; };
//clearly it matters how mutable you need your equivalence relationships to be,,
//in this implementation, if an element's equivalence relation changes then
//the element is going to be erased and re-inserted.
virtual void eqValue(const class E& other)
{
if (_eqValue == other._eqValue) return;
eqRemove();
_eqValue=other._eqValue;
E::Elementals.insert(this);
};
ES::iterator eqRemove()
{
auto range=E::Elementals.equal_range(this);
//worst-case complexity should be aprox linear over the range
for (auto it=range.first; it!=range.second; it++)
if (this == (*it))
return E::Elementals.erase(it);
return E::Elementals.end();
}
std::string Name; //some other attribute unique to the instance
static ES Elementals; //canonical set of elements with equivalence relations
protected:
size_t _eqValue=0;
};
size_t E::_faucet=0;
E::ES E::Elementals{};
//////////////////////////////////////
//random specialisation providing
//dynamic class-level equivalence
class StarFish : public E
{
public:
static void EqAssign(const class E& other)
{
if (StarFish::_id == other.eqValue()) return;
E el(StarFish::_id);
auto range=E::Elementals.equal_range(&el);
StarFish::_id=other.eqValue();
E::EL insertList(range.first, range.second);
E::Elementals.erase(range.first, range.second);
E::Elementals.insert(insertList.begin(), insertList.end());
}
StarFish() : E("starfish") {}
//base-class overrides
virtual size_t eqValue() const { return StarFish::_id; };
protected: //equivalence is a the class level
virtual void eqValue(const class E& other) { assert(0); }
private:
static size_t _id;
};
size_t StarFish::_id=E::NewValue();
//////////////////////////////////////
void eqPrint(const E& e)
{
std::cout << std::endl << "elementals equivalent to " << e.Name << ": ";
auto range=E::Elementals.equal_range(&e);
for (auto it=range.first; it!=range.second; it++)
std::cout << (*it)->Name << " ";
std::cout << std::endl << std::endl;
}
//////////////////////////////////////
void eqPrint()
{
for (auto it=E::Elementals.begin(); it!=E::Elementals.end(); it++)
std::cout << (*it)->Name << ": " << (*it)->eqValue() << " ";
std::cout << std::endl << std::endl;
}
//////////////////////////////////////
int main()
{
E e0{"zero"}, e1{"one"}, e2{"two"}, e3{"three"}, e4{"four"}, e5{"five"};
//per the OP
e0=e1=e2;
e3=e4;
e5=e3;
eqPrint(e0);
eqPrint(e3);
eqPrint(e5);
eqPrint();
StarFish::EqAssign(e3);
StarFish starfish1, starfish2;
starfish1.Name="fred";
eqPrint(e3);
//re-assignment
StarFish::EqAssign(e0);
e3=e0;
{ //out of scope removal
E e6{"six"};
e6=e4;
eqPrint(e4);
}
eqPrint(e5);
eqPrint(e0);
eqPrint();
return 0;
}
online demo
NB: C++ class inheritance also provides another kind of immutable equivalence that can be quite useful ;)