I'm adapting to an interface with parameter const vector<pair<int32_t, A>>& as.
To avoid multi-construct and multi-destruct, I write CreateAs as follow.
I was expecting it to trigger create move del each for once, but it turned out triggered move and del for twice.
What's the reason?
I made this way so that the A objects could destroy themselves automatically, even with new but without delete. Am I doing it right?
To reproduce it: https://repl.it/#unix1/ShrillFirsthandAdvance
#include <iostream>
#include <vector>
using namespace std;
struct A {
A() { cout << "A()" << endl; }
A(int32_t a) : a_(a) { cout << "Create A: " << a << endl; }
A(const A& oa) { a_ = oa.a_; cout << "Copy A: " << oa.a_ << endl; }
A(A& oa) { a_ = oa.a_; cout << "Copy A non-const: " << oa.a_ << endl; }
A(const A&& oa) { a_ = oa.a_; cout << "Move A: " << oa.a_ << endl; }
A(A&& oa) { a_ = oa.a_; cout << "Move A non-const: " << oa.a_ << endl; }
~A() { cout << "Del A: " << a_ << ", ptr: " << this << endl; }
int32_t a_;
};
void CreateAs(vector<pair<int32_t, A>>& as) {
as.reserve(3);
for (int32_t i = 0; i < 3; ++i) {
A* a = new A(i*i);
cout << "a ptr: " << &a << endl;
cout << "-----before insert----" << endl;
as.emplace_back(make_pair(i, move(*a)));
cout << "-----after insert-----" << endl;
}
}
void Test() {
vector<pair<int32_t, A>> as;
cout << "-----Create begin----" << endl;
CreateAs(as);
cout << "-----Create end------" << endl;
for (const auto& item : as) {
cout << item.first << "->" << item.second.a_ << endl;
}
}
int main(int32_t argc, char* argv[]) {
Test();
cout << "____end test____" << endl;
return 0;
}
make_pair constructs an A in a pair. emplace_back moves the pair and therefore A into the vector. The moved from pair is destroyed, also destroying the contained A.
To avoid any move, you might do
void CreateAs(std::vector<std::pair<int32_t, A>>& as) {
as.reserve(3);
for (int32_t i = 0; i < 3; ++i) {
as.emplace_back(i, i*i);
}
}
Demo
You currently have extra move with your extra make_pair.
Related
#include <iostream>
class Vector
{
public:
int size;
int* contents;
int capacity;
Vector();
~Vector();
void PushFront(int value);
//void Vector(int initialCapacity);
void PushBack(int value);
int& At(int index);
int& operator[](int index);
void Clear();
int Size();
bool IsEmpty();
void Resize(int newSize);
void Reserve(int newCapacity);
int GetCapacity();
void EraseAt(int index);
void Erase(int value);
int Find(int value);
bool Contains(int value);
void Insert(int value, int index);
};
So these are the function declarations I used for the other file, these are included for reference.
#pragma once
#include <iostream>
#include <string>
#include "Header.h"
//double* vPointer;
double* vPointer;
int* myArray[];
Vector::Vector()
{
std::cout << "Vector Class Created." << std::endl;
capacity = 10,
contents = new int[capacity],
size = 0;
}
Vector::~Vector() // Deallocates any memory the container needed to allocate
{
delete[] vPointer;
std::cout << "Vector Class Deallocated." << std::endl;
}
void Vector::PushFront(int value) // Adds a single value to beginning of the container
{
for (int i = 0; i <= size; ++i)
{
if (value < vPointer[capacity])
{
Reserve(capacity + 1);
}
if (i == value)
{
std::cout << "testing." << std::endl;
}
if (i > value)
{
std::cout << "testing (code 2)." << std::endl;
}
}
}
void Vector::PushBack(int value) // Adds a single value to end of the container
{
if (size == capacity)
{
Reserve(capacity + 1);
}
contents[size] = value;
size++;
};
void Vector::Reserve(int newCapacity) // Allocates room for at least this many values. Does not shrink the storage
{
if (capacity < newCapacity)
{
int* newArray = new int[newCapacity];
for (int i = 0; i < size; i++)
{
newArray[i] = contents[i];
}
delete[] contents;
contents = newArray;
capacity = newCapacity;
}
}
int& Vector::At(int index) // Return a reference to the element at the given index. If unable, throws an exception.
{
return contents[index];
}
int& Vector::operator[](int index) // Return a reference to the element at the given index. If unable, throws an exception.
{
std::cout << contents[index] << std::endl;
return contents[index];
}
void Vector::Clear() // Remove all elements from the container
{
size = 0;
}
int Vector::Size() // Returns the number of elements in this container
{
return size;
std::cout << size;
}
bool Vector::IsEmpty() // Returns whether or not the container has any elements
{
std::cout << "Container has the following number of elements: " << vPointer << std::endl;
return vPointer;
}
void Vector::Resize(int newSize) // Adds or removes elements from the end of the container to achieve the given new size
{
if (newSize < size)
{
size == newSize;
std::cout << newSize << std::endl;
}
else if (newSize > capacity)
{
Reserve(newSize);
size == newSize;
return;
}
else
{
std::cout << "something went wrong! Attempting to ReSize Anyways..." << std::endl;
size = newSize;
std::cout << "Vector Resized. newSize = " << newSize << std::endl;
}
}
int Vector::GetCapacity() // Returns the amount of allocated space
{
return capacity;
}
void Vector::EraseAt(int index) // Removes the value at the given index, decreasing the contained size
{
for (int i = 0; i < size; i++)
{
if (vPointer[i] == index)
{
std::cout << "semi-functional." << std::endl;
}
}
}
void Vector::Erase(int value) // Removes one value from the container: the first that matches
{
for (int i = 0; i < size; i++)
{
if (value == vPointer[i])
{
vPointer[i] = vPointer[i + 1];
}
else
{
//cout << "can't erase a value that does not exist." << endl;
return;
}
}
}
int Vector::Find(int value) // Returns the index of the given value, -1 if not found
{
for (int i = 0; i < size; i++)
{
if (value == vPointer[i])
{
std::cout << "Value Found : " << i << std::endl;
return i;
}
else
{
return -1;
std::cout << "Value Not Found" << std::endl;
}
if (value != vPointer[i])
{
std::cout << "Value Found : " << i << std::endl;
return i;
}
}
}
bool Vector::Contains(int value) // Returns true if this value is in the container
{
for (int i = 0; i < size; i++)
{
if (value < size)
{
std::cout << "The Value " << value << " Is In The Container." << std::endl;
return value;
return true;
}
else
{
std::cout << "The Value Is Not Within The Container." << std::endl;
return false;
}
}
}
void Vector::Insert(int value, int index) // Insert the given element at the given position. Position 0 should insert the element at the beginning of the container
{
}
Its Here ^^^ where I'm having the problems. Some of the things I try to program don't want to work at all, and I can't use the because the project is to make a 'vector' class using arrays. I'm lost as how to insert an integer into an array in this case, because I can't find the array that we allocated. Teacher says its here, but I can't seem to call it at all.
#include <iostream>
#include "Header.h"
#include <vector>
//using namespace std;
int main(int argc, char* argv[])
{
Vector myVector;
std::cout << "Initializing 'Vector' Array..." << std::endl;
std::cout << " " << std::endl;
std::cout << "myVector.PushBack():" << std::endl;
//myVector.PushBack
myVector.PushBack(3);
std::cout << "Should be 3: " << myVector.At(0) << std::endl;
std::cout << " " << std::endl;
std::cout << "myVector.Reserve():" << std::endl;
//myVector.Reserve
std::cout << "Capacity: " << myVector.capacity << std::endl;
myVector.Reserve(15);
std::cout << "Should allocate 5 slots in the array: " << std::endl;
std::cout << "New Capacity: " << myVector.capacity << std::endl;
//myVector.At
std::cout << " " << std::endl;
std::cout << "myVector.At():" << std::endl;
std::cout << "Testing myVector.At(#) with value of 0... : " << myVector.At(0) << std::endl;
//myVector GetCapacity
std::cout << " " << std::endl;
std::cout << "myVector.GetCapacity():" << std::endl;
myVector.GetCapacity();
std::cout << "Capacity of Array: " << myVector.capacity << std::endl;
//myVector.Resize() -not working-
std::cout << " " << std::endl;
std::cout << "myVector.Resize():" << std::endl;
std::cout << "Orignal Vector Size: " << myVector.size << std::endl;
myVector.Resize(12);
//myVector Clear() + myVector Size()
std::cout << " " << std::endl;
std::cout << "myVector Clear() + myVector Size():" << std::endl;
myVector.Clear();
std::cout << "clearing myVector... Current Size:" << myVector.Size() << std::endl;
//myVector IsEmpty()
std::cout << " " << std::endl;
std::cout << "myVector.IsEmpty();:" << std::endl;
myVector.IsEmpty();
std::cout << " " << std::endl;
std::cout << "myVector.Operator[]:" << std::endl;
//myVector.operator[](int index)
myVector.operator[](3);
std::cout << myVector.Size() << std::endl;
std::cout << "NEEDS DEBUGGING:" << std::endl;
//-not working - :
//myVector Erase
std::cout << " " << std::endl;
std::cout << "myVector.Erase:" << std::endl;
myVector.Erase(3);
std::cout << myVector.Size() << std::endl;
std::cout << myVector.GetCapacity() << std::endl;
std::cout << " " << std::endl;
std::cout << "myVector.EraseAt:" << std::endl;
//myVector EraseAt
myVector.EraseAt(3);
std::cout << " " << std::endl;
std::cout << "myVector.Contains:" << std::endl;
//myVector.Contains()
myVector.Contains(0);
std::cout << " " << std::endl;
std::cout << "myVector.Find:" << std::endl;
//myVector.Find()
myVector.Find(0);
std::cout << " " << std::endl;
std::cout << "myVector.PushFront():" << std::endl;
//myVector.PushFront(3);
//myVector.PushFront(3);
std::cout << " " << std::endl;
std::cout << "myVector.Insert:" << std::endl;
//myVector.Insert()
//myVector.~Vector(); THIS FUNCTIONS!
std::cout << " " << std::endl;
std::cout << "myVector.~Vector()" << std::endl;
myVector.~Vector();
//std::cout << "Memory DeAllocated." << std::endl;
std::cin.get();
}
These parts are just me testing them out in the main file. A few things are marked as broken, because they don't work. I'm more focused on fixing PushFront and Insert if anyone could help me. I tried looking online but I can't seem to find something I understand.
Just PushBack the element, and then rotate it into place
void Vector::Insert(int value, int index) // Insert the given element at the given position. Position 0 should insert the element at the beginning of the container
{
PushBack(value);
std::rotate(contents + index, contents + size - 1, contents + size);
}
I've tried to understand the semantics of c++ temporary objects lifetime extension. I've tried to simulate simple situation and was a bit surprised.
Below I'm providing my code.
#include <iostream>
struct C
{
C(const int new_a) { a = new_a; };
int a = 0;
};
C return_num()
{
C num(20);
std::cout << "From func(): num = " << num.a << ", by adress: " << &num.a << std::endl;
return num;
}
void pass_num(const C& num)
{
std::cout << "From func(): num = " << num.a << ", by adress: " << &num.a << std::endl;
}
int main()
{
std::cout << "\nLifetime extention:" << std::endl;
{
const C& ext_num = return_num();
std::cout << "From main(): num = " << ext_num.a << ", by adress: " << &ext_num.a << std::endl;
}
std::cout << "\nPassing by reference:" << std::endl;
{
C num(20);
std::cout << "From main(): num = " << num.a << ", by adress: " << &num.a << std::endl;
pass_num(num);
}
}
Here is the main question: return_num() works curiously from my point of view, cause I expected that address of the variable, which I'm trying to output in main, would be the same as internally in return_num(). Could you please explain me why it is not?
For example in pass_num() output address matches the external address which I got in main.
Here is example output:
Lifetime extention:
From func(): num = 20, by adress: 0x7fff44fc8b4c
From main(): num = 20, by adress: 0x7fff44fc8b70
Passing by reference:
From main(): num = 20, by adress: 0x7fff44fc8b6c
From func(): num = 20, by adress: 0x7fff44fc8b6c
Move constructors typically "steal" the resources held by the argument (e.g. pointers to dynamically-allocated objects, file descriptors, TCP sockets, I/O streams, running threads, etc.) rather than make copies of them, and leave the argument in some valid but otherwise indeterminate state.
Please see Move Constructor
I changed the below in your code and I hope it is working as expected. I changed int a to int* a
#include <iostream>
class C
{
public:
int *a;
C( int new_a)
{
a = new int();
*a = new_a;
};
C(const C& rhs) { std::cout << "Copy " << std::endl; this->a = rhs.a; }
C(C&& rhs):a(std::move(rhs.a))
{
std::cout << "Move!!" <<"Address resource a " << &(*a) << ", Address of
resource rhs.a" << &(*rhs.a) << std::endl; rhs.a = nullptr;
std::cout << "Value of a:: " << *a << std::endl;
}
};
C return_num()
{
C num(20);
std::cout << "From return_num(): num = " << *num.a << ", Address of resource a :
"<< &(*num.a)<< std::endl;
return (std::move(num));
}
void pass_num(const C& num)
{
std::cout << "From pass_num(): num = " << *num.a << ", by adress: " << &num.a <<
std::endl;
}
int main()
{
std::cout << "\nLifetime extention:" << std::endl;
{
const C& ext_num = return_num();
std::cout << "From main() 1 : num = " << *(ext_num.a) << ", by resource
adress: " << &(*ext_num.a) << std::endl;
}
std::cout << "\nPassing by reference:" << std::endl;
{
C num(20);
std::cout << "From main() 2 : num = " << *num.a << ", by adress: " << &num.a
<< std::endl;
pass_num(num);
}
return 0;
}
The above code produces below output:
Lifetime extention:
From return_num(): num = 20, Address of resource a : 0x7fffeca99280
Move!!Address resource a 0x7fffeca99280, Address of resource rhs.a0x7fffeca99280
Value of a:: 20
From main() 1 : num = 20, by resource adress: 0x7fffeca99280
Passing by reference:
From main() 2 : num = 20, by adress: 0x7ffff466f388
From pass_num(): num = 20, by adress: 0x7ffff466f388
I hope it helps!
Imagine this function:
int getNumber(){
int num = 10;
return num;
}
This function does not return num as an object, it returns a no-named copy of it (r-value, if you will) with the same value. Therefore, it has a different address.
The same thing happens with your return_num function.
I suspect that taking the address of a member is inhibiting the optimization because the compiler doesn't know how to deal with all the possible edge cases. Eliminating taking the address of the member makes the optimization work.
#include <iostream>
struct C
{
C(const int new_a) { a = new_a; };
int a = 0;
struct C* t = this;
};
C return_num()
{
C num(20);
std::cout << "From func(): num = " << num.a << ", by adress: " << num.t << std::endl;
return num;
}
void pass_num(const C& num)
{
std::cout << "From func(): num = " << num.a << ", by adress: " << num.t << std::endl;
}
int main()
{
std::cout << "\nLifetime extention:" << std::endl;
{
const C& ext_num = return_num();
std::cout << "From main(): num = " << ext_num.a << ", by adress: " << ext_num.t << std::endl;
}
std::cout << "\nPassing by reference:" << std::endl;
{
C num(20);
std::cout << "From main(): num = " << num.a << ", by adress: " << num.t << std::endl;
pass_num(num);
}
}
Lifetime extention:
From func(): num = 20, by adress: 0x7ffd61f48a50
From main(): num = 20, by adress: 0x7ffd61f48a50
Passing by reference:
From main(): num = 20, by adress: 0x7ffd61f48a90
From func(): num = 20, by adress: 0x7ffd61f48a90
I'm trying to execute the following code:
#include <iostream>
using namespace std;
class ABC {
private:
int x, y;
public:
ABC(){
cout << "Default constructor called!" << endl;
ABC(2, 3);
cout << x << " " << y << endl;
}
ABC(int i, int j){
cout << "Parameterized constructor called with parameters "<< i << " " << j << "!" << endl;
x = i;
y = j;
cout << x << " " << y << endl;
}
};
int main(){
ABC a;
return 0;
}
I am getting the following output:
Default constructor called!
Parameterized constructor called with parameters 2 3!
2 3
-858993460 -858993460
Shouldn't the member variables be initialized with values 2 and 3?
ABC(2, 3); doesn't call the constructor to initialize the members, it just create a temporary variable which will be destroyed immediately.
If you meant delegating constructor you should:
ABC() : ABC(2, 3) {
cout << "Default constructor called!" << endl;
cout << x << " " << y << endl;
}
Note this is a C++11 feature. You can add a member function if you can't use C++11.
class ABC {
private:
int x, y;
init(int i, int j) {
x = i;
y = j;
}
public:
ABC(){
cout << "Default constructor called!" << endl;
init(2, 3);
cout << x << " " << y << endl;
}
ABC(int i, int j){
cout << "Parameterized constructor called with parameters "<< i << " " << j << "!" << endl;
init(i, j);
cout << x << " " << y << endl;
}
};
You create a temporary variable in ABC() body. You can use this syntax to overcome this:
class ABC
{
private:
int x, y;
public:
ABC() : ABC(2,3)
{
std::cout << "Default constructor called!" << std::endl;
}
ABC(int i, int j)
{
std::cout << "Parameterized constructor called with parameters "<< i << " " << j << "!" << std::endl;
x = i;
y = j;
std::cout << x << " " << y << std::endl;
}
};
I have this sample code below. I know little bit about RVO (return value optimization) and how copy constructor and assignment operator are skipped during the optimization and return of the value is placed directly on the memory on the left. So if shared pointer does the RVO how does the shared pointer know when to increase its counter? Because for some reason I thought shared pointer class would know when to increase counter based on the number copies or assignment it made.
#include <iostream>
#include <memory>
using namespace std;
class A{
public:
A(){}
A(const A& other){ std::cout << " Copy Constructor " << std::endl; }
A& operator=(const A&other){
std::cout << "Assingment operator " << std::endl;
return *this;
}
~A(){
std::cout << "~A" << std::endl;
}
};
std::shared_ptr<A> give_me_A(){
std::shared_ptr<A> sp(new A);
return sp;
}
void pass_shared_ptr_by_val(std::shared_ptr<A> sp){
std::cout << __func__ << ": count sp = " << sp.use_count() << std::endl;
std::shared_ptr<A> sp1 = sp;
std::cout << __func__ << ": count sp = " << sp.use_count() << std::endl;
std::cout << __func__ << ": count sp1 = " << sp1.use_count() << std::endl;
}
void pass_shared_ptr_by_ref(std::shared_ptr<A>& sp){
std::cout << __func__ << ": count sp = " << sp.use_count() << std::endl;
std::shared_ptr<A> sp1 = sp;
std::cout << __func__ << ": count sp = " << sp.use_count() << std::endl;
std::cout << __func__ << ": count sp1 = " << sp1.use_count() << std::endl;
}
int main(){
{
shared_ptr<A> sp3 = give_me_A();
std::cout << "sp3 count = " << sp3.use_count() << std::endl;
pass_shared_ptr_by_val(sp3);
pass_shared_ptr_by_ref(sp3);
}
return 0;
}
output:
sp3 count = 1
pass_shared_ptr_by_val: count sp = 2
pass_shared_ptr_by_val: count sp = 3
pass_shared_ptr_by_val: count sp1 = 3
pass_shared_ptr_by_ref: count sp = 1
pass_shared_ptr_by_ref: count sp = 2
pass_shared_ptr_by_ref: count sp1 = 2
~A
If there is no copy, nothing needs to be counted.
If RVO is in play no copy is made, so why would the ref-count need to be increased? There is no extra object to destroy and decrement the ref-count.
I want to pass an function as argument. I know you can pass a function pointer like the first test in my example, but is it possible to pass a hold function (not a pointer) like my second test?
#include <iostream>
using namespace std;
/* variable for function pointer */
void (*func)(int);
/* default output function */
void my_default(int x) {
cout << "x =" << "\t" << x << endl << endl;
}
/* entry */
int main() {
cout << "Test Programm\n\n";
/* 1. Test - default output function */
cout << "my_default\n";
func = &my_default; // WORK! OK!
func(5);
/* 2. Test - special output function 2 */
cout << "my_func2\n";
func = void my_func1(int x) {
cout << "x =" << " " << x << endl << endl;
}; // WON'T WORK! FAILED!
func(5);
return 0;
}
In C++ 11, you can pass a lambda:
func = [](int x) { cout << "x =" << " " << x << endl << endl; };
EDIT: lambdas can return values:
func = [](int x)->int{ cout << "x =" << " " << x << endl << endl; return x; };
With c++11, you can write such code in a lot simpler way:
Instead of writing function signature use auto
auto func = &my_default; // WORK! OK!
func(5);
you can also use std::function objects to pass them around:
template<typename T>
void callme(std::function<T> f) {
f(6);
}
std::function<decltype(my_default)> func1 = &my_default;
func(5);
callme(func1);
and also you can use lambdas:
/* 2. Test - special output function 2 */
cout << "my_func2\n";
auto fun = [](int x) {
cout << "x =" << " " << x << endl << endl;
};
fun(5);
Even with return value it work:
#include <iostream>
using namespace std;
/* variable for function pointer */
int (*func)(int);
/* default output function */
int my_default(int x) {
//cout << "x =" << "\t" << x << endl << endl;
return x;
}
/* entry */
int main() {
cout << "Test Programm\n\n";
/* 1. Test - default output function */
cout << "my_default\n";
func = &my_default; // WORK! OK!
cout << func(5) << endl << endl;
/* 2. Test - special output function 2 */
cout << "my_func2\n";
func = [](int x) {
//cout << "x =" << " " << x << endl << endl;
return x;
};
cout << func(5) << endl << endl;
return 0;
}
You can uses lamdas:
std::function<int(int)> func2 = [](int i) { return i+4; };
std::cout << "func2: " << func2(6) << '\n';
if the body consists of the single return statement, the return type
is the type of the returned expression (after rvalue-to-lvalue,
array-to-pointer, or function-to-pointer implicit conversion)
If you lamda constains not single return statamen you should specify return type
std::function<int(int)> func2 = [=](int i) ->int {
if (globalVar)
return i*4;
else
return 4;
};
std::cout << "func2: " << func2(6) << '\n';