Which one to choose between pointer way and non pointer way? - c++11

#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.

Related

c++ std transform calls copy constructor multiple times

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);
}

why map emplace calling rvalue constructor twice

class twoMem {
int _a;
int _b;
public:
twoMem() {
std::cout << "default constructor" << std::endl;
}
twoMem(int a, int b) :_a(a), _b(b) {
std::cout << "constructor called" << std::endl;
}
twoMem(const twoMem& other) {
std::cout << "copy constructor called" << std::endl;
_a = other._a;
_b = other._b;
}
twoMem(const twoMem&& other) {
std::cout << "rvalue copy constructor called" << std::endl;
_a = other._a;
_b = other._b;
}
~twoMem() {
std::cout << "destructor called" << std::endl;
}
};
int main()
{
std::map<std::string, twoMem> myMap{};
myMap.emplace(std::make_pair("foo", twoMem{ 1, 2 }));
return 0;
}
output:
constructor called
rvalue copy constructor called
rvalue copy constructor called
destructor called
destructor called
destructor called
First, make_pair moves from twoMem argument into pair<const char*, twoMem> it returns. Second, emplace() moves from that into actual node.
Make it
myMap.emplace("foo", twoMem{ 1, 2 });
then the move constructor is only called once. That's kind of the point of map::emplace.
You can get to zero copy or move constructors this way:
myMap.emplace(std::piecewise_construct, std::make_tuple("foo"), std::make_tuple(1, 2));
Though arguably this cure may be worse than the disease, as now you are constructing and copying tuples around, which is likely at least as expensive as copying twoMem.

What does String do that I'm not doing? c++11

I am still new to c++, so bear with me.
I was trying to learn more about how std::move works and I saw an example where they used std::move to move the string to a different function and then showed using std::cout that no string remained. I thought cool, let's see if I can make my own class and do the same:
#include <iostream>
#include <string>
class integer
{
private:
int *m_i;
public:
integer(int i=0) : m_i(new int{i})
{
std::cout << "Calling Constructor\n";
}
~integer()
{
if(m_i != nullptr) {
std::cout << "Deleting integer\n";
delete m_i;
m_i = nullptr;
}
}
integer(integer&& i) : m_i(nullptr) // move constructor
{
std::cout << "Move Constructor\n";
m_i = i.m_i;
i.m_i = nullptr;
}
integer(const integer& i) : m_i(new int) { // copy constructor
std::cout << "Copy Constructor\n";
*m_i = *(i.m_i);
}
//*
integer& operator=(integer&& i) { // move assignment
std::cout << "Move Assignment\n";
if(&i != this) {
delete m_i;
m_i = i.m_i;
i.m_i = nullptr;
}
return *this;
}
integer& operator=(const integer &i) { // copy assignment
std::cout << "Copy Assignment\n";
if(&i != this) {
m_i = new int;
*m_i = *(i.m_i);
}
return *this;
}
int& operator*() const { return *m_i; }
int* operator->() const { return m_i; }
bool empty() const noexcept {
if(m_i == nullptr) return true;
return false;
}
friend std::ostream& operator<<(std::ostream &out, const integer i) {
if(i.empty()) {
std::cout << "During overload, i is empty\n";
return out;
}
out << *(i.m_i);
return out;
}
};
void g(integer i) { std::cout << "G-wiz - "; std::cout << "The g value is " << i << '\n'; }
void g(std::string s) { std::cout << "The g value is " << s << '\n'; }
int main()
{
std::string s("Hello");
std::cout << "Now for string\n";
g(std::move(s));
if(s.empty()) std::cout << "s is empty\n";
g(s);
std::cout << "\nNow for integer\n";
integer i = 77;
if(!i.empty()) std::cout << "i is " << i << '\n';
else std::cout << "i is empty\n";
g(i);
std::cout << "Move it\n";
g(std::move(i)); // rvalue ref called
if(!i.empty()) std::cout << "i is " << i << '\n';
else std::cout << "i is empty\n";
g(i);
return 0;
}
And this is my output:
Now for string
The g value is Hello
s is empty
The g value is
Now for integer
Calling Constructor
Copy Constructor
i is 77
Deleting integer
Copy Constructor
G-wiz - Copy Constructor
The g value is 77
Deleting integer
Deleting integer
Move it
Move Constructor
G-wiz - Copy Constructor
The g value is 77
Deleting integer
Deleting integer
i is empty
Copy Constructor
Process returned 255 (0xFF) execution time : 7.633 s
Press any key to continue.
As you can see, it crashes when it enters g the second time, never even getting to the operator<<() function. How is it that the empty std::string s can be passed to g where my empty integer i crashes the program?
Edit: Fixed new int vs. new int[] error. Thanks n.m.
Your "empty integer" crashes the program because it contains a null pointer. You are trying to dereference it when you use it at the right hand side of the assignment.
An empty string is a normal usable string. There are no unchecked null pointer dereferences in the std::string code.
You have to ensure that the empty state of your object is a usable one. Start with defining a default constructor. Does it make sense for your class? If not, then move semantic probably doesn't either. If yes, a moved-from object in the move constructor should probably end up in the same state as a default-constructed object. A move assignment can act as a swap operation, so there the right-hand-side may end up either empty or not.
If you don't want to define a usable empty state for your class, and still want move semantics, you simply cannot use an object after it has been moved from. You still need to make sure that an empty object is destructible.

Address of an instance emplaced to std::vector is invalid

I have 2 std::vectors:
to first vector, I emplace instance
to second vector, I want to store the address of the instance just emplaced
But it does not work, i.e., the stored address differs from the emplaced instance's address.
If it matters at all, I'm on Linux and using g++ 5.1 and clang 3.6 with -std=c++11.
Here's a working example to illustrate the problem.
#include <iostream>
#include <vector>
struct Foo {
Foo(int a1, int a2) : f1(a1), f2(a2) {}
int f1;
int f2;
};
int main(int, char**) {
std::vector<Foo> vec1;
std::vector<Foo*> vec2;
int num = 10;
for (int i = 0; i < num; ++i) {
vec1.emplace_back(i, i * i);
// I want to store the address of *emplaced* instance...
vec2.push_back(&vec1.back());
}
// same
std::cout << "size 1: " << vec1.size() << std::endl;
std::cout << "size 2: " << vec2.size() << std::endl;
// same for me
std::cout << "back 1: " << &vec1.back() << std::endl;
std::cout << "back 2: " << vec2.back() << std::endl;
// typically differ ?
std::cout << "front 1: " << &vec1.front() << std::endl;
std::cout << "front 2: " << vec2.front() << std::endl;
for (int i = 0; i < num; ++i) {
std::cout << i + 1 << "th" << std::endl;
// same for last several (size % 4) for me
std::cout << "1: " << &vec1[i] << std::endl;
std::cout << "2: " << vec2[i] << std::endl;
}
}
Questions
Is it correct behavior ? I guess it's caused by storing the address of temporary instance but I want to know whether it's permitted by the standard (just curious).
If above is true, how to work around this ? I resolved this by changing first one to vector<unique_ptr<Foo>> but is there any idiomatic way ?
Two options:
1) You can simply fix your test. You just need in you test preallocate enough memory first with
vec1.reserve(10);
Well, this is implementation details for std::vector. As more and more items are added to std::vector it needs to get more space for them. And this space must be contigious. So when there is not enough space for a new element std::vector allocates a bigger block of memory, copies existing elements to it, add the new element and finally frees the block of memory that it used before. As a result addresses that you stored in vec2 might become invalid.
However, if you preallocate enough memory for 10 elements then you code is correct.
Or, since reserving memory is sort of tricky thing to do
2) use std::deque since insertion and deletion at either end of a deque never invalidates pointers or references to the rest of the elements (http://en.cppreference.com/w/cpp/container/deque) and forget about the problem with invalidated addresses. So no need to reserve memory.

Vector move semantic c++11

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.

Resources