#include <iostream>
struct Data
{
std::shared_ptr<char[]> m_name = nullptr; // char* m_name = nullptr;
// bool m_owner = false;
Data() = default;
Data(const char* name)
{
using std::copy;
int size = strlen(name) + 1;
m_name = std::make_unique<char[]>(size); // m_name = new char[size];
copy(name, name + size, m_name.get());
// m_owner = true;
}
// ~Data()
// {
// if (/*m_name &&*/ m_owner)
// delete[] m_name;
// m_name = nullptr;
// }
void print()
{
using std::cout, std::endl;
if (!m_name)
return;
int size = strlen(m_name.get());
for(int i = 0; i < size; ++i)
cout << m_name[i];
cout << endl;
}
};
void shallow_copy(Data& dst, Data& src)
{
dst.m_name = src.m_name;
}
void deep_copy(Data& dst, Data& src)
{
using std::copy;
int size = strlen(src.m_name.get())+1;
dst.m_name = std::make_unique<char[]>(size); // dst.m_name = new char[size];
copy(src.m_name.get(), src.m_name.get() + size, dst.m_name.get());
// dst.m_owner = true;
}
int main()
{
using std::cout, std::endl;
cout << "starting..." << endl;
auto data1 = new Data{"abc"};
data1->print();
auto data2 = new Data();
data2->print();
// shallow_copy(*data2, *data1);
deep_copy(*data2, *data1);
// delete data1;
data2->print();
}
While trying to replace char* by std::shared_ptr<char[]> above, I noticed things get a little more verbose with copy, going from
copy(src.m_name, src.m_name + size, dst.m_name);
to
copy(src.m_name.get(), src.m_name.get() + size, dst.m_name.get());
Is there a better (shorter) way than typing that .get() every time?
Is there a better (shorter) way than typing that .get() every time?
Not when using smart pointers, no. Best you can do is call .get() earlier and save the pointer for reuse, eg:
char *ptr = src.m_name.get();
copy(ptr, ptr + size, dst.m_name.get());
Alternatively, in this particular example, you can use std::copy_n() instead of std::copy(), eg:
copy_n(src.m_name.get(), size, dst.m_name.get());
If you know the std::shared/unique_ptr<char[]> won't go out of scope immediately, you can grab a the underlying pointer beforehand and use that. It makes the lines where you use the address look a little neater at the cost of an extra line or two. I personally think it's worth the cost.
const char* const src_ptr = src.m_name.get();
char* const dst_ptr = dst.m_name.get();
// assume m_name for either stays in scope until the next line completes
std::copy(src_ptr, src_ptr + size, dst_ptr);
Related
I have to optimize a really crappy c++ code. The guy who made it doesn't know how to code: It has memory stomps, indices are used starting from 1 instead of 0, spagetthi code, you name a bad practice and there it is.
So 40% of the time this algorithm is copying large arrays which are nearly empty. I'm trying to make minimal changes because that would probably mean changing thousands and thousands lines of code and any mistake would mean getting completely different results.
So instead of declaring this large, nearly empty arrays like this:
short HLLE[dimcl]; //define dimcl 600
I'm doing something like this
ArrayTimes HLLE;
/////
// Stores the occupied positions in another array, when copying, instead of copying all, empty the occupied ones
// then fill with the other occupied ones
class ArrayTimes
{
public:
ArrayTimes(int numTasks);
ArrayTimes(const ArrayTimes& _other);
virtual ~ArrayTimes();
inline short& operator[](int _index)
{
auto &result = (*m_times)[_index];
if (result == 0) //if there was already a value doesn't count as occupied again
{
(*m_occupied)[m_numOccupied] = _index;
++m_numOccupied;
}
return result;
}
inline const short& operator[](int _index) const
{
return (*m_times)[_index];
}
inline ArrayTimes& operator= (const ArrayTimes &_other)
{
//vaciamos
for (int i = 0; i < m_numOccupied; ++i)
{
auto occIndex = m_occupied->operator[](i);
m_times->operator[](occIndex) = 0;
}
*m_occupied = *(_other.m_occupied);
m_numOccupied = _other.m_numOccupied;
for (int i = 0; i < _other.m_numOccupied; ++i)
{
auto occIndex = _other.m_occupied->operator[](i);
m_times->operator[](occIndex) = _other.m_times->operator[](occIndex);
}
return *this;
}
ArrayTimes::ArrayTimes(int numTasks) :
m_numOccupied(0)
{
m_occupied = new std::vector<int>();
m_times = new std::vector<short>();
m_times->resize(numTasks);
m_occupied->resize(numTasks / 4);
}
ArrayTimes::ArrayTimes(const ArrayTimes& _other)
{
m_occupied = new std::vector<int>();
m_times = new std::vector<short>();
auto datosGlobales = DatosGlobalesProblema::getInstance();
auto numTareas = datosGlobales->GetNumTareas() + 1;
m_occupied = new std::vector<int>();
m_times = new std::vector<short>();
m_times->resize(numTareas);
m_occupied->resize(numTareas / 4);
operator=(_other);
}
ArrayTimes::~ArrayTimes()
{
delete m_times;
delete m_occupied;
}
int ArrayTimes::Size() const
{
return m_occupied->size();
}
I have tried several containers to store the occupied positions: list, set, unordered set, map. None of them is quicker than copying all the array positions.
I guess the right answer is finding another way to save that information without wasting memory in such arrays of memory, altough that means refactoring thousands of lines of code.
The following code has this timings with 300 to 600 copy. You don't need to copy anything manually with std::vector.
I've changed the = operator but you have to go through one of the vectors to see what you have to copy.
Also you can have more m_times than indexes in m_occupied so you shouldn't count on occupied vector.
Size: 300, 75
Element: 90
real 0m0,002s
user 0m0,002s
sys 0m0,000s
class ArrayTimes
{
std::vector<int> m_occupied;
std::vector<short> m_times;
int m_numOccupied;
public:
ArrayTimes(int numTasks) :
m_numOccupied(0)
{
m_times.resize(numTasks);
m_occupied.resize(numTasks / 4);
}
ArrayTimes(const ArrayTimes& _other)
{
auto numTareas = 600;
m_times.resize(numTareas);
m_occupied.resize(numTareas / 4);
operator=(_other);
}
~ArrayTimes()
{
}
inline short& operator[](int _index)
{
auto &result = m_times[_index];
if (result == 0) //if there was already a value doesn't count as occupied again
{
m_occupied[m_numOccupied] = _index;
++m_numOccupied;
}
return result;
}
inline const short& operator[](int _index) const
{
return m_times[_index];
}
inline ArrayTimes& operator= (const ArrayTimes &_other)
{
m_times.reserve (_other.m_times.size());
for (auto e : _other.m_occupied) {
m_times[e] = _other.m_times[e];
}
m_numOccupied = _other.m_numOccupied;
return *this;
}
int OSize() const
{
return m_times.size();
}
int Size() const
{
return m_occupied.size();
}
};
int main ()
{
ArrayTimes a1(600);
ArrayTimes a2(300);
a2[3] = 9;
a1 = a2;
std::cout << "Size: " << a1.OSize() << ", " << a1.Size() << std::endl;
std::cout << "Element: " << a1[3] << std::endl; // copied value from a2
return 0;
}
I managed to shrink the array to few elements, so there is no need of this tricky class.
Thanks for pointing out my mistakes, at least I learned something from this experience
I've read many posts with the same error, unfortunately all of those deal with indexing off the end of an array. In my case I get the error when I assign the array to a variable in my constructor.
Here is my code:
Heap.cpp
#include "./Heap.h"
#include <iostream>
#include <sstream>
// Provides floor, ceil, etc.
#include <cmath>
using namespace std;
Heap::Heap() {
arraySize = 0;
n = 0;
A = NULL;
}
// This assumes that every element of the array is an
// element of the heap.
Heap::Heap(int* inArray, int inArraySize, int inHeapSize) {
// TODO: initialize your class data members. An array dynamically allocated
// as follows:
// A = new int[size];
// If you allocate an array like this you MUST deallocate it in your
// destructor. This is done for you in the destructor below.
arraySize = inArraySize;
n = inHeapSize;
A = new int[arraySize];
A = inArray;
}
// Destructor. Cleans up memory.
Heap::~Heap() {
delete [] A;
}
// Note: the function name is prefixed by Heap:: (the class
// name followed by two colons). Any function defined in
// the .cpp file must have this prefix.
int Heap::at(int i) const {
return A[i];
}
int Heap::parent(int i) const{
return (int) (i - 1) / 2;
}
int Heap::left(int i) const {
return (i + 1)* 2 - 1;
}
int Heap::right(int i) const {
return (i + 1) * 2;
}
bool Heap::hasLeft(int i) const {
int leftIndex = left(i);
std::cout << "left index = " << leftIndex<< std::endl;
return false;
}
bool Heap::hasRight(int i) const{
return false;
}
void Heap::maxHeapify(int i){
}
//
void Heap::buildMaxHeap(){
}
bool Heap::operator==(const Heap& rhs) {
if (n != rhs.n) return false;
for (int i = 0; i < n; ++i) {
if (A[i] != rhs.A[i]) return false;
}
return true;
}
bool Heap::operator==(const int* rhs) {
for (int i = 0; i < n; ++i) {
if (A[i] != rhs[i]) return false;
}
return true;
}
std::ostream& operator<<(std::ostream& out, const Heap& h) {
out << "[";
for (int i = 0; i < h.n; ++i) {
out << h.A[i];
if (i < h.n-1) {
out << ", ";
}
}
out << "]";
return out;
}
string toDotImpl(const Heap& h, int i) {
using namespace std;
stringstream ss;
if (h.hasLeft(i)) {
ss << toDotImpl(h, h.left(i));
ss << "\"" << h.at(i) << "\" -> \""
<< h.at(h.left(i)) << "\"\n";
}
if (h.hasRight(i)) {
ss << toDotImpl(h, h.right(i));
ss << "\"" << h.at(i) << "\" -> \""
<< h.at(h.right(i)) << "\"\n";
}
return ss.str();
}
string toDot(const Heap& h) {
using namespace std;
stringstream ss;
ss << "digraph G {\n";
ss << "graph [ordering=\"out\"]\n";
ss << "\"" << h.at(0) << "\"\n";
ss << toDotImpl(h, 0);
ss << "}\n";
return ss.str();
}
and
Heap.h
#pragma once
// Provides I/O
#include <iostream>
// Provides size_t
#include <cstdlib>
// Provides INT_MAX and INT_MIN
// You can consider INT_MIN to be negative infinity
// and INT_MAX to be infinity
#include <climits>
//------------------------------------------------------------
// Heap class
//------------------------------------------------------------
class Heap {
public:
// Constructor
Heap();
// This constructor assumes that every element of the array is an
// element of the heap.
Heap(int* inArray, int inArraySize, int inHeapSize);
// Destructor
~Heap();
// Accesses an element of the array.
int at(int i) const;
// Gets parent index of element at i
int parent(int i) const;
// Return element to the left of i
int left(int i) const;
// Return element to the right of i
int right(int i) const;
// Checks if an element has a left child
bool hasLeft(int i) const;
// Checks if an elemnt has a right child
bool hasRight(int i) const;
// "Max heapifies" an array
void maxHeapify(int i);
// builds a max heap
void buildMaxHeap();
// Allows comparison between results
bool operator==(const Heap& rhs);
bool operator==(const int* rhs);
// Useful for debugging. To use:
// Heap h;
// cout << h << endl;
friend std::ostream& operator<<(std::ostream& out, const Heap& h);
private:
// The array
int* A;
// Size of the array
int arraySize;
// The number of elements in the heap
int n;
};
// Useful for debugging. To use:
// Heap h;
// cout << h << endl;
std::string toDot(const Heap& h);
The code is called with I can include the entire main.cpp if needed but it has several hundred lines of just test cases that are commented out.
int A[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
Heap h(A, 8, 8);
if I comment out A = inArray; the program runs so I'm pretty confident that is where the issue is.
A is defined in Heap.h as `int* A;
Here is the full error:
*** Error in `./project': free(): invalid size: 0x00007ffd84786660 ***
Aborted (core dumped)
this is probably quite a simple issue, but I can't figure out what is causing this since I believe this should allocate an array of size inArraySize of type int and then assign the given array inArray to A.
Full disclosure: this is part of an assignment so feel free to just point me in the right direction, but my professor is fine with us using stackoverflow as long as we site it.
You're trying to copy an array, but assigning pointers like that is not how to do it. There are various ways.
Standard C++:
#include <algorithm>
std::copy(inArray, inArray + inArraySize, A);
Using standard containers:
#include <vector>
std::vector<int> A(inArray, inArray + inArraySize);
Old style C way
memcpy(A, inArray, sizeof(int) * inArraySize);
Doing:
A = new int[arraySize];
A = inArray;
Is like doing:
i = 5;
i = 6;
The second assignment overrides the first one.
Hence as a result, the member variable A is pointing to the same memory block pointed by the input argument inArray.
If you haven't dynamically allocated this memory block (with new), then you cannot dynamically deallocate it (with delete).
The lines
A = new int[arraySize];
A = inArray;
are cause of two problems.
There is a memory leak. The value returned by new int[arraySize] is lost and cannot be deallocated.
If you are calling delete [] A in the destructor, that would be cause of the second problem.
If inArray was dynamically allocated and deallocated in the calling function, you will be calling delete on the same pointer twice.
If inArray was an array created in the stack, calling delete on it is also a problem. delete can be called only on memory that was returned by call to new.
A = inArray; is not doing what you think it is doing. This line does not copy inArray into the memory you allocated for A. Instead it changes A to point to a new location (the address of inArray), causing the previously allocated memory to leak. Later on when you call delete on A you'll be trying to free memory at inArray's address.
If you just want to copy an array, you could do something like
A = new int[inArraySize];
for (i = 0; i < inArraySize; ++i)
A[i] = inArray[i];
Or better yet, with std::copy:
std::copy(inArray, inArray + inArraySize, A);
I have to create a copy constructor for my object, which look like this;
class DTable {
private:
std::string s_name;
int* *array;
int size;
public:
DTable();
DTable(std::string sName);
DTable(DTable &pcOther);
~DTable();
void vSetName(std::string sName);
std::string info();
int getValue(int index, bool &ok);
bool setValue(int index, int val);
const int defaultArrSize = 10;
const std::string defaultArrName = "Default Name";
};
Where array variable points at array of int*. Copy constructor i came up with looks like this;
DTable::DTable(DTable & pcOther) {
s_name = pcOther.s_name + "_copy";
size = pcOther.size;
array = new int*[size];
for (int i = 0; i < size; i++) {
array[i] = new int;
*array[i] = pcOther.*array[i];
}
}
The problem is that, i just cannot copy values of pointed int array to another array. Solution like this leaves me with error
expression must have pointer to member type
Also,
array[i] = pcOther.array[i];
is wrong, because that just copies references, so after altering one object, copy of it will be altered too. I want to avoid that.
I'd love to use different structure for this, but it has to be dynamically allocated array of int*
You can use the memcpy(),
void * memcpy ( void * destination, const void * source, size_t num );
or
*array[i] = *(pcOther.array[i])
for e.g.
DTable::DTable(DTable & pcOther) {
s_name = pcOther.s_name + "_copy";
size = pcOther.size;
array = new int*[size];
for (int i = 0; i < size; i++) {
array[i] = new int;
*array[i] = *(pcOther.array[i]);
// or
memcpy ( array[i], pcOther.array[i] , sizeof(int)*1 );
}
}
This error occurs during run time, and I'm not sure what's causing it - the code looks correct to me.
#include <iostream>
#include <string>
using namespace std;
struct Room {
int d_noSeat;
bool d_hasProjector;
Room() = default;
Room(const Room& r);
};
class Event {
Room* d_room;
std::string d_name;
public:
Event();
Event(const Event& e);
~Event();
void set(Room r, const std::string& name);
void print();
};
Event::Event() : d_room(0), d_name("") {};
void Event::print() {
std::cout << "Event: " << d_name;
if (d_room != 0) {
std::cout << " in size " << d_room->d_noSeat;
if (d_room->d_hasProjector)
std::cout << " with";
else
std::cout << " without";
std::cout << " projector";
}
std::cout << std::endl;
return;
}
void printEvent(Event e) {
e.print();
return;
}
void Event::set(Room r, const std::string& name) {
d_room = &r;
d_name = name;
}
// Room shallow copy constructor
Room::Room(const Room& r) :
d_noSeat(r.d_noSeat),
d_hasProjector(r.d_hasProjector)
{ }
// Event deep copy constructor
Event::Event(const Event& e) :
d_name(e.d_name),
d_room(new Room(*e.d_room))
{ }
// Event destructor
Event::~Event()
{
delete[] d_room;
}
int main() {
const int noLect = 5;
Room r;
Event lectures[noLect];
for (int i = 0; i < noLect; ++i) {
r.d_noSeat = i + 1;
r.d_hasProjector != r.d_hasProjector;
lectures[i].set(r, "CSI2372");
lectures[i].print();
}
std::cout << "-------------------" << std::endl;
for (int i = 0; i < noLect; ++i) {
printEvent(lectures[i]);
}
return 0;
}
The error apparently occurs at line 52 (first line in the print() function). In addition to this, the printed text displays numbers that are very large and often negative. What is causing this?
Issue
void Event::set(Room r, const std::string& name)
{
d_room = &r;
// ^
d_name = name;
}
You are referencing to the temporary object: Room r passed by value, which is destroyed at the end of the scope: }.
Instead you must reallocate the member pointer:
d_room = new Room(r);
Why it went wrong
Because you are writing C-style code in C++ classes.
In C++ we tend to:
Avoid naked pointers, prefer smart pointers:
class Event
{
std::shared_ptr<Room> d_room;
...
Event::~Event() { /* no need to delete */ }
Use constructor overloading (instead of using set-like functions after construction):
Event(Room& r, const std::string& name):
d_room(new Room(r)),
d_name(name)
{}
Pass by reference:
void set(Room& r, const std::string& name);
Avoid raw arrays, use STL facilities instead:
std::vector<Event> lectures;
// or
std::array<Event, 5> lectures;
Another issue
r.d_hasProjector != r.d_hasProjector; // checks if r.d_hasProject is not itself
You probably want
r.d_hasProjector = !r.d_hasProjector;
Complete code: link
Also, here is a must-read link about advanced C++ stuff which, I believe, will be very useful to you: http://www.parashift.com/c++-faq/
Edit: I forgot about your question:
In addition to this, the printed text displays numbers that are very large and often negative. What is causing this?
Those numbers are garbage. Variables that are not explicitly initialized are not initialized at all. Memory is allocated but holds old information from previous program. It could contain anything. When you read from uninitialized variables, you'll get this garbage. You had a pointer which was pointing to a destroyed object. So the pointer was effectively uninitialized.
Your problem is here:
void Event::set(Room r, const std::string& name) {
d_room = &r;
d_name = name;
}
The &r takes the address of an object whose lifetime ends when the function returns, resulting in undefined behaviour when you later try to access it.
If you want to use pointers, you need to allocate them dynamically:
void Event::set(Room* r, const std::string& name) {
d_room = r;
d_name = name;
}
// ...
for (int i = 0; i < noLect; ++i) {
Room* r = new Room;
r->d_noSeat = i + 1;
r->d_hasProjector != r.d_hasProjector;
lectures[i].set(r, "CSI2372");
lectures[i].print();
}
// ...
But it doesn't look like you need pointers here, you should be able to have
Room d_room;
in the Event class.
Hey i'm new to c++ and still working out its perticularities. I'm having the darnedest time trying to figure out whats going wrong with this code. I've stepped through it and everything is calculating correctly. The issue is that value_array in the base class doesn't seem to be retaining the values once the derived class Calculate function ends. I think i've declared and allocated the array properly. I'm stumped...
#include <iostream>
class Indicator
{
protected:
double * value_array;
double * input_array;
int input_size;
public:
Indicator(double input[], int size)
{
input_array = input;
input_size = size;
value_array = new double[size]; // issue with value_array
}
double operator[] (int index) { return value_array[index]; }
void virtual Calculate() {}
~Indicator() { delete[] value_array; }
};
class SMA : public Indicator
{
private:
int nperiod;
double sum;
public:
SMA(double input[], int size, int period) : Indicator(input, size)
{
nperiod = period;
sum = 0;
Calculate();
}
void Calculate();
};
void SMA::Calculate()
{
for (int i=0; i<input_size; i++)
{
if (i > nperiod - 1)
{
sum += input_array[i] - input_array[i-nperiod];
value_array[i] = sum / nperiod;
}
else
{
sum += input_array[i];
value_array[i] = sum / (i+1);
}
}
}
int main(int argc, const char *argv[]) {
double input[] = {1,2,3,4,5,6,7,8,9,10};
Indicator indicator = SMA(input,10,5);
double value = indicator[0];
std::cout << "value: " << value << std::endl;
std::cin.get();
exit(0);
}
Update:
Here is the code implemented with vectors. I wanted to leave the input as double[] to be consistent with other libraries, any other potential issues I should be aware of?
#include <iostream>
#include <vector>
class Indicator
{
protected:
std::vector<double> value_vector;
double * input_array;
int input_size;
public:
Indicator(double input[], int size)
{
input_array = input;
input_size = size;
value_vector.reserve(size);
}
double operator[] (int index) { return value_vector[index]; }
void virtual Calculate() {}
};
class SMA : public Indicator
{
private:
int nperiod;
double sum;
public:
SMA(double input[], int size, int period) : Indicator(input, size)
{
nperiod = period;
sum = 0;
Calculate();
}
void Calculate();
};
void SMA::Calculate()
{
for (int i=0; i<input_size; i++)
{
if (i > nperiod - 1)
{
sum += input_array[i] - input_array[i-nperiod];
value_vector.push_back(sum / nperiod);
}
else
{
sum += input_array[i];
value_vector.push_back(sum / (i+1));
}
std::cout << "sma: " << value_vector[i] << std::endl;
}
}
int main(int argc, const char *argv[]) {
double input[] = {1,2,3,4,5,6,7,8,9,10};
Indicator indicator = SMA(input,10,5);
for (int i=0; i<10; i++)
{
std::cout << "main: " << indicator[i] << std::endl;
}
std::cin.get();
exit(0);
}
That's because you're violating the Rule of Three. Since your class manages a resource, it needs a copy constructor and an assignment operator. I strongly suggest replacing any T* data member with a std::vector<T> data member. Then you don't need to write those special member functions manually.
Hia,
a few things are wrong.
As FredOverflow says you need a copy constructor and assignment, something like:
Indicator::Indicator(const Indicator& other)
{
input_size = other.input_size;
//direct copy of reference as indicator doesn't own this data
//Note a shared pointer (such as boost::shared_ptr) would be better than a naked reference
input_array = other.input_array;
//construct a new set of data
value_array = new double[input_size];
//do you want to copy the data too? maybe a memcpy follows?
memcpy(value_array, other.value_array, input_size*sizeof(double));
}
Then you need an assignment
Indicator&
Indicator::operator=(const Indicator& other)
{
//make sure you are not assigning itself
if(this != &other)
{
input_size = other.input_size;
//direct copy of reference as indicator doesn't own this data
//Note a shared pointer (such as boost::shared_ptr) would be better than a naked reference
input_array = other.input_array;
//destroy old data and construct a new set of data
delete[] value_array;
value_array = new double[input_size];
//do you want to copy the data too? maybe a memcpy follows?
memcpy(value_array, other.value_array, input_size*sizeof(double));
}
return *this;
}
You probably also want to make the destructor virtual - see here for why -
it helps prevent memory leaks in the destructor of SMA
virtual ~Indicator() { delete[] value_array; }
Use std::vector instead of raw arrays.
std::vector handles all the memory management and copying and so forth.
Cheers & hth.,