Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 24 days ago.
Improve this question
I was told that you should avoid using pointers or new in c++ but I could not figure out how. I implemented dynamic array with iterator class. Here is the code:
Custom vector and iterator:
#include <iostream>
template<class T> class Myvector{
private:
int size;
int capacity;
T* objects;
void add_capacity(){
int newCapacity = capacity * 2 +1;
T *newArray = new T[ newCapacity ];
for( int i = 0; i < size; ++i )
newArray[ i ] = std::move( objects[ i ] );
capacity = newCapacity;
std::swap( objects, newArray );
delete [ ] newArray;
}
public:
Myvector(){
objects = new T[1];
capacity = 1;
size = 0;
}
void add(T obj){
if (capacity == size){
add_capacity();
}
objects[size] = obj;
size += 1;
}
class Iterator
{
public:
T* operator->() { return ptr; }
Iterator(T *p) {
ptr= p;
}
Iterator operator++() {
++ptr;
return *this;
}
bool operator!=(const Iterator & other) const{return ptr != other.ptr;}
const T & operator*() const{return *ptr;}
private:
T * ptr; // Pointer to v.
};
Iterator begin() {
//return &objects[0];
return Iterator(&objects[0]);
}
Iterator end(){
//return &objects[size];
return Iterator(&objects[size]);
}
};
So the question is that is is possible to implement this without pointers or new? I want to get better in c++.
What you heard is true. You should avoid raw owning pointers and new whenver possible.
Just don't miss the last part: "whenever possible". Raw owning pointers and new are not completely banned. They are tools that have their applications. Using an array with dynamic size is not one of them. There is std::vector. Use it.
Whenever you think you need to use new and a raw owning pointer you should revisit <memory> for smart pointers and the containers library. It is rare to not find what you need in there. And if you don't you will use a third party library rather than implementing your own container.
However, if we are talking about reimplementing std::vector (which you wouldn't do usually, but lets say you did), then things are different.
If you look at implementation of std::vector you will find that it does use raw pointers. The point is that this usage of raw pointers is encapsulated. std::vector grants you access to a pointer to the underlying array, but you never have to worry about calling delete on that pointer.
Your MyVector fails to manage ownership of the data it allocates. It has no destructor, it cannot be copied and it has more issues. If you do write a class that manages a ressource (can be a raw owning pointer, can be something else) you need to read about the rule of 3/5. Though, what you should follow whenever possible is the rule of 0 (at the end of the linked article).
This last suggestion, "prefer rule of 0", is basically just "prefer container and smart pointer" for class members. Both "rules" help you to write simpler code. Code that has on average less bugs. You can choose to not follow the suggestion, but then you are on your own. Then you must take care to correctly manage the resources. And if you fail to do so you will be in trouble.
Related
This question already has answers here:
C++: Replace raw pointers with shared and weak ptr
(4 answers)
Replacing existing raw pointers with smart pointers
(5 answers)
Closed 4 years ago.
I'm trying to understand how can I substitute raw pointers on my C++ software with smart-pointers.
I have the following code:
class Foo
{
private:
std::vector<Bar *> m_member;
};
Now in some function I populate that vector with:
m_member.push_back( new Bar() );
and when my program finishes I delete the memory with:
for( std::vector<Bar *>::iterator it = m_member.begin(); it < m_member.end(); ++it )
{
delete (*it);
(*it) = NULL;
}
Now all this is good.
The problem is as I see it comes from the fact that at one point of time I may need to delete one of the member from the vector (this member is user-specified).
Now this is easy:
for(...)
{
if( (*it)->GetFieldFromBar() == <user_specified_condition> )
{
delete (*it);
(*it) = NULL;
}
}
But how do I re-write it with the smart pointers? Is it even possible?
It's actually far easier with smart pointers, and here unique_ptr.
Population is done through:
m_member.push_back(std::make_unique<Bar>()); // C++14, you can use std::unique_ptr<Bar>(new Bar) is you only have C++11
No need for a destructor.
For custom deletion:
for(auto& p: m_member)
{
if( p->GetFieldFromBar() == <user_specified_condition> )
{
p.reset();
}
}
Yes, using std::vector<std::unique_ptr<Bar>> is ideal in this case. You clearly have ownership in the vector.
Adding elements to it can be done the following in c++14:
m_member.push_back( std::make_unique<Bar>() );
Removing all elements gets reduced to: m_member.clear() or even just letting it go out of scope.
Selectively removing the elements is better done like:
m_member.erase(std::remove_if(m_member.begin(), m_member.end(), [&](auto &&ptr) { return ptr->GetFieldFromBar() == <user_specified_condition>; }), m_member.end());
A bit descriptive for dealing with all elements, though, you can wrap it in a function to get rid of the boiler plate.
This question already has answers here:
How to delete an element from a vector while looping over it?
(6 answers)
Closed 9 years ago.
I use a vector of shared pointers to contain some game characters called customer.
typedef std::shared_ptr<Customer> customer;
std::vector<customer> customers;
customers.push_back(customer(new Customer()));
for(int i = 0; i < customers.size(); i++)
{
if(customers[i]->hasLeftScreen())
{
if(!customers[i]->itemRecieved())
outOfStocks++;
// Kill Character Here
}
}
I have used vectors to hold objects before so am used to calling erase on the vector and passing in the iterator. My question is there a way of deleting a the pointer from the vector in the above code snippet? I was hoping not to use an iterator here to simplify the code. I also need to delete the pointer because I was the customer to be removed from the game once it has left the screen.
Many thanks
Consider using an iterator, which frankly will be much easier to deal with. I'm not sure of your aversion to them, but see below:
std::vector<customer>::iterator it = customers.begin();
while (it != customers.end())
{
if(it->hasLeftScreen())
{
if(!it->itemRecieved())
outOfStocks++;
it = customers.erase(it);
continue;
}
++it;
}
This will remove the shared pointer instance from the vector. If the instance is the last reference to the shared pointer it will also release the associated memory of said Customer, firing its destructor, etc... (somewhat the point of using smart shared pointers in the first place, and props for using smart pointers, by the way).
You should always use iterators; it's a C++ idiom. This would change the code to...
for(auto i = customers.begin(); i != customers.end(); ++i)
{
if((*i)->hasLeftScreen())
{
if(!(*i)->itemRecieved())
outOfStocks++;
// Kill Character Here
}
}
Now, it is clear, we use the erase-remove idiom instead.
int outOfStocks = 0;
auto it = std::remove_if(customer.begin(), customers.end(), [&](Customer const& i) {
if(i->hasLeftScreen()) {
if(!i->itemRecieved()) {
outOfStocks++;
}
return true;
}
return false;
}
std::erase(it, customers.end());
You can also take advantage of "iterator arithmetic":
// Kill Character Here
customers.erase(customers.begin() + i);
... but that has a problem that customers.size() and the current index will get invalidated as the container will shrink.
Also, you don't need to explicitly delete the customer you're removing, because the smart pointer will take care of that.
I maintain a old C++ application which has a lot of classes like below:
class ClassWithALotOfVectors
{
std::vector<int> _vector1;
std::vector<int> _vector2;
// a lot of other vector datamembers go here
std::vector<double> _vectorN;
};
that is - a data type where members a vectors of double or int.
The thing is - these vectors are never populated at the same time - and therefore
when we create 100000 instances of ClassWithALotOfVectors - memory usage adds up
to impressive number even though only 10% of these vector are in use.
So I decided to write a small "allocate on demand" vector class.
It is a wrapper around std::vector - where internal vector only create when
accessed for the first time (using two getters - ref() & const_ref() methods)
When I replaced std::vector in a ClassWithALotOfVectors class with a compact_vector
as below:
class ClassWithALotOfVectors2
{
compact_vector<int> _vector1;
compact_vector<int> _vector2;
compact_vector<double> _vectorN;
};
did a few tests and the results were promising - memory usage went down
dramatically, but suddenly found that application does not release memory
at the end - the memory consumptions grows in much slower rate than it
is used to be - but application does not seem to be deallocating the memory
at the end.
Can you look at my implementation of the compact_vector
and see if you can spot something wrong with a memory management.
template <class T> class compact_vector
{
public:
compact_vector<T>()
:_data(NULL)
{
}
~compact_vector<T>()
{
clear();
}
compact_vector<T>(const compact_vector<T> & rhs)
:_data(NULL)
{
if (NULL != rhs._data)
{
_data = new std::vector<T>(*(rhs._data));
}
else
{
clear();
}
}
// assignment
//
compact_vector<T> & operator=(const compact_vector<T> & rhs)
{
if (this != &rhs)
{
clear();
if (NULL != rhs._data)
{
_data = new std::vector<T>(*rhs._data);
}
}
return *this;
}
compact_vector<T> & operator=(const std::vector<T> & rhs)
{
clear();
if (!rhs.empty())
{
_data = new std::vector<T>(rhs);
}
return *this;
}
const std::vector<T> & const_ref()
{
createInternal();
return *_data;
}
std::vector<T> & ref()
{
createInternal();
return *_data;
}
void clear()
{
if (NULL != _data)
{
_data->clear();
delete _data;
_data = NULL;
}
}
private:
void createInternal()
{
if (NULL == _data)
{
_data = new std::vector<T>();
}
}
private:
compact_vector<T>(const std::vector<T> & rhs)
{
}
compact_vector<T>(std::vector<T> & rhs)
{
}
compact_vector<T>(std::vector<T> rhs)
{
}
std::vector<T> * _data;
};
Most implementations of std::vector don't acquire memory until you need it, and the size of a vector is usually just a few (3 + possibly extra debug information) pointers. That is, std::vector<int>() will not allocate space for any object. I believe that you are barking at the wrong tree here.
Why is your original code having a much higher memory usage? Are you expecting clear() to release memory?
If so you are mistaken. The clear() function destroys the contained elements but does not release the allocated memory. Consider adding a wrapper to clear the memory that uses the following idiom:
std::vector<int>().swap( _data );
What the previous line does is creating a new empty vector (usually no memory attached, not mandated, but common implementation) and swapping the contents of the two vectors. At the end of the expression, the temporary contains the data that was originally held by the _data vector and _data is empty and with no memory (implementation defined). The temporary is destructed at the end of the full expression and memory is released.
Alternatively, if your compiler supports C++11, you can use shrink_to_fit() after calling clear(). The standard does not require shrink_to_fit() to actually shrink to fit, but for an empty vector I would expect the implementation to do it. Test it by calling capacity() after the call and seeing whether it has gone down to 0 or not.
Use smart pointers. In this case, std::unique_ptr with hand-made copy ctor / assignment operator. Suddenly, all your problems are solved. It's like magic!
Sorry to sound so snarky, but memory leaks always have the same answer: smart pointer.
Since you are saying it's an old application and can't do much with it. How about having all the vectors having zero size reserved during construction.
It's tedious, but since old app and not much is expected to be modified. May be worth the effort for once.
class ClassWithALotOfVectors
{
std::vector<int> _vector1;
std::vector<int> _vector2;
// a lot of other vector datamembers go here
std::vector<double> _vectorN;
public:
ClassWithALotOfVectors() : Init() { }
void Init()
{
vector1.reserve(0);
/// Like wise other vectors.
}
};
The idea that only one vector at a time is ever in use sounds like the union concept. Sure enough, C++ has an element called an anonymous union that does precisely this.
class ClassWithALotOfVectors {
public:
union {
std::vector<double> _vector1;
std::vector<double> _vector2;
};
ClassWithALotOfVectors() { new(&_vector1) std::vector<double>; };
~ClassWithALotOfVectors() { _vector1.~vector<double>(); };
};
Because the union can't know which element's constructor to call, default constructors are disabled in the union and you have to manually construct and deconstruct the union's element, but I think this will accomplish what you are looking for, aliasing _vector1 and _vector2 to the same element but placing both in the ClassWithALotOfVectors namespace, then deallocating the vector when the destructor for ClassWithALotOfVectors is called.
For more on anonymous unions see:
CPP reference: Anonymous Unions
I'm fairly new to C++ and new to pointers as well. I'm currently working on a stack and was trying to reallocate the memory for the stack as the size of the stack reaches the top however, I'm running into issues. I've already done a lot of research both on Google and stack overflow and have found some information helpful but since I'm so new to stacks and C++ I'm still having issues. I was hoping some bright and intelligent people could at least point me in the right direction.
now... Here's my code.
#include <iostream>
#define STACKMAX 20
using namespace std;
template <class T> class StackTemplated {
private:
int top;
T values[STACKMAX];
public:
StackTemplated();
void push(T i);
T pop(void);
bool empty(void);
};
template <class T> StackTemplated<T>::StackTemplated() {
top = -1;
}
template <class T>void StackTemplated<T>::push(T i) {
if (top == STACKMAX - 1) {
// reallocate top of stack. (this is the area I'm having issues)
char * string1;
string1 = (char *)calloc(STACKMAX, sizeof(char));
if (top == STACKMAX - 1) {
cout << "The stack didn't re-allocate.";
exit(1);
}
} else {
top++;
values[top] = i;
}
}
template <class T> T StackTemplated<T>::pop(void) {
if (top < 0) {
printf("%", "Stack underflow!");
exit(1);
} else {
return values[top--];
}
}
template <class T> bool StackTemplated<T>::empty() {
return (top == -1);
}
Here's a list of a few things I noticed:
STACKMAX is a constant. If you're expanding the stack, how will you keep track of how big it currently is?
The values member is a fixed-size array. You won't be able to change the size of it dynamically without changing how this is declared and allocated.
calloc() allocates a new chunk of memory with the number of bytes you specify. You'll need to somehow copy the existing stack into the new memory block, and free the previous one.
You're allocating only STACKMAX bytes in the call to calloc(). You'll probably want to scale this by sizeof T, in case T is not a char.
There will be a lot of details for you to fix up once you address these major points. Good luck.
The problem is that you don't want to reallocate the top of the stack. Rather, you want to allocate a new array of values which is large enough to hold the new values. Also, since you need to reallocate the array, values should be a pointer.
But how about we forget all this. If we're working in c++, let's use what c++ offers us to make our lives easier. After that's done, then try open things up, if you really feel the need.
One of the things I'm referring to is your use of calloc. Using calloc is a bad idea, particularly when using templates. The problem is that since calloc has no type information, it won't do something as basic as calling a constructor. Constructors are very important in OOP, since they guarantee that an object's invariance when it is created. Instead, use the new[] keyword, like
values = new T[STACKMAX];
This allocates an array of T of STACKMAX length. Of course, as Greg points out, you should reconsider the use of STACKMAX, and use a variable instead. Also, values shouldn't be a static array, but should instead have type T*.
Another thing I was referring to is the fact that you are really trying to implement an array which grows dynamically as needed. In c++, we call such a structure a vector. If you use a vector, your entire code reduces to
#include<iostream>
#include<vector>
using namespace std;
template<class T> class StackTemplated {
private:
std::vector<T> vec;
public:
StackTemplated() { } // the constructor is trivial; in fact, you can leave it out if you want
void push(T i);
T pop(void);
bool empty(void);
};
template<class T>
void StackTemplated<T>::push(T i) {
vec.push_back(i);
}
template<class T>
T StackTemplate<T>::pop(void) {
T top = vec.back();
vec.pop_back();
return top;
}
template<class T>
bool StackTemplate<T>::isEmpty(void) {
return vec.size() == 0;
}
That's all. It's a lot less hairy if you can use an existing data structure to implement the new data structure.
Once you get really comfortable with how a vector works (and there's plenty of explanations / documentation on the web), then try implementing the functionality yourself. Bottom line is, implementing a data structure is a lot easier if you know exactly how it's supposed to behave.
I would declare your values like
T* vaules;
Then use new to create it not calloc. You will need to keep track of the top of the stack and size of it. As Greg says when you grow the stack make sure and copy data over and clean up the old one.
So having
struct ResultStructure
{
ResultStructure(const ResultStructure& other)
{
// copy code in here ? using memcpy ? how???
}
ResultStructure& operator=(const ResultStructure& other)
{
if (this != &other) {
// copy code in here ?
}
return *this
}
int length;
char* ptr;
};
How to implement "copy constructor" and "assignment operator"? (sorry - I am C++ nube)
Update: sbi and others ask - why do I want to manually deal with raw memory? My answer is simple - In a students project I am part of now we use lots of C library's such as for example OpenCV OpenAL and FFmpeg and there are more to come. Currently using C++ we try to create a graph based direct show like cross platform library that would be helpful in live video broadcasting and processing. Our graph elements currently use char* and int pairs for data exchange. To cast data to subscribed elements we use raw memcpy now. I want to go further and make it possible for us to make our graph elements base C++ template. So that one graph element would be capable of of sharing current graph element data with other Graph elements and that data it shares would be a structure that would contain not one char* one int but any number of data fields and nearly any elements inside. So that is why I need to understand how to create a basic C++ structure that implements "copy constructor" and "assignment operator" for me to be capable to use new for us data casting algorithms like
void CastData(T item){
for(size_t i = 0 ; i < FuncVec.size(); i++){
T dataCopy = item;
FuncVec[i](dataCopy);
}
}
instead of currently used
void CastData(char * data, int length){
for(size_t i = 0 ; i < FuncVec.size(); i++){
char* dataCopy = new char[length];
memcpy(dataCopy, data, length);
FuncVec[i](dataCopy, length);
delete[] dataCopy;
}
}
You might want to explain why you want to manually deal with raw memory. I haven't done this in a long time, it's what std::string and std::vector where designed for:
struct ResultStructure
{
// nothing else needed
std::string data; // or std::vector<char>
};
But if you really need to do this the hard way (is this homework?), then be advised that it is, at first, surprisingly hard to get this right. For example, a naive implementation of the assignment operator might be like this:
// DON'T TRY THIS AT HOME!!
ResultStructure& ResultStructure::operator=(const ResultStructure& rhs)
{
delete[] ptr; // free old ressource
ptr = new char[rhs.length]; // allocate new resourse
std::copy(rhs.ptr, rhs.ptr+rhs.length, ptr; // copy data
length = rhs.length;
}
If someone accidentally assigns an object to itself (which might happen if all you have is two references and you don't suspect them to refer to the same object), then this will fail fatally.
Also, what if new throws an exception? (It might throw std::bad_alloc if memory is exhausted.) Then we have already deleted the old data and have not allocated new data. The pointer, however, still points at where the old data used to be (actually, I think this is implementation-defined, but I have yet to see an implementation that changes a ptr upon deletion), and the class' destructor (you knew that class would need a destructor, right?) would then attempt to delete a piece of data at an address where no data is allocated. That's Undefined Behavior. The best you can hope for is that it crashes immediately.
The easiest way to do this is to employ the Copy-And-Swap idiom:
struct ResultStructure
{
ResultStructure(const ResultStructure& other)
: ptr(new char[rhs.length]), length(rhs.length)
{
std::copy(rhs.ptr, rhs.ptr+rhs.length, ptr);
}
~ResultStructure() // your class needs this
{
delete[] ptr;
}
ResultStructure& operator=(ResultStructure rhs) // note: passed by copy
{
this->swap(rhs);
return *this
}
void swap(const ResultStruct& rhs)
{
using std::swap;
swap(length, rhs.length);
swap(ptr, rhs.ptr);
}
std::size_t length;
char* ptr;
};
Note that I have added a destructor, changed the assignment operator to pass the argument per copy (we need the copy constructor invoked to allocate memory), and added a swap member function. Per convention a swap() function never throws and is fast, preferably O(1).
I know that GMan's discussion of the Copy-And-Swap idiom is exhaustive enough to be and exhausting while mine is probably too terse for you, and you will likely not understand a lot of it at first, but try to persevere and to understand as much as possible.
If you use std::string, instead of char*, you would not even need to write operator= or copy-constructor. The compiler generated code would do your job very well.
But as a general solution (for some other scenario), use copy-and-swap idiom:
Copy-and-Swap Idiom
What is the copy-and-swap idiom?
Exceptional C++ by Herb Sutter has described these in great detail. I would recommend you to read items from this book. For the time being, you can read this article online:
Exception-Safe Generic Containers
The easy solution is to use a std::string instead of char* member.
Then the compiler-generated copy constructor and copy assignment operator just work.
As a rule, and especially as a novice, don't have raw pointer members.
Cheers & hth.,
As has been said, and as was recommending in the question this emanated from, you should probably reuse an existing container. At least the code would be right :)
For educational purposes though, let's examine this structure:
class Result
{
public:
private:
size_t length; // can't really be negative, right ?
char* data;
};
Here, we need explicit memory management. This implies, notably, following the Rule Of Three (say thanks to Fred)
Let's begin with actually building our object:
Result::Result(): length(0), data(0) {}
Result::Result(size_t l, char* d): length(0), data(0)
{
if (!d) { return; }
data = new char[l]; // this may throw, so we do it first
length = l;
memcpy(data, d, l);
}
Now we can implement the traditional operators:
// Swap
void Result::swap(Result& other)
{
using std::swap;
swap(length, other.length);
swap(data, other.data);
}
// Copy Constructor
Result::Result(Result const& other): length(0), data(0)
{
if (!other.length) { return; }
data = new char[other.length];
length = other.length;
mempcy(data, other.data, length);
}
// Assignemt Operator
Result& Result::operator=(Result other)
{
this->swap(other);
return *this;
}
// !IMPORTANT!
// Destructor
Result::~Result()
{
delete[] data; // use the array form of delete
// no need to test for nullity, it's handled
}
this is std::vector<char>'s job - or is this homework?
the vector would replace both length and the allocation behind ptr. the vector is the c++ idiom, and you'll not make friends with other c++ devs if you implement your classes like you've described. of course, there are corner cases, but standard containers such as vector are the default.
the vector knows how to copy chars as well as itself, and the implementations are optimized and tested.
here's how to explicitly implement copy ctor/assign using a vector:
struct ResultStructure {
ResultStructure(const ResultStructure& other) : d_chars(other.d_chars) {
}
ResultStructure& operator=(const ResultStructure& other) {
if (this != &other) {
this->d_chars = other.d_chars;
}
return *this;
}
std::vector<char> d_chars;
};
I think this should do the work:
struct ResultStructure
{
ResultStructure(const ResultStructure& other);
ResultStructure& operator=(const ResultStructure& other);
int length;
char* ptr;
};
ResultStructure::ResultStructure(const ResultStructure& other):length(other.length)
{
ptr = (char*)malloc(length);
memcpy(ptr, other.ptr, length);
}
ResultStructure& ResultStructure::operator=(const ResultStructure& other)
{
length = other.length;
ptr = (char*)malloc(length);
memcpy(ptr, other.ptr, length);
return *this;
}
Please remember about freeing ptr in destructor.
What is stored under ptr? If text, why not to use std::string? Anyway you can use std::vector. The constructors will be much easier then...
How is the memory to which ptr points allocated?
if using new, allocate with new, set length and then copy
other.length = length;
other.ptr = new char[length];
memcpy( other.ptr, ptr, length );
If you're allocating the memory with malloc, substitute a call to malloc in place of the call to new. If you're using some other memory scheme, figure it out. :)