Fruits class:
#include <string>
using namespace std;
class Fruits {
string color;
public:
Fruits() {
color = "r";
}
};
Main:
#include "Fruits.cpp"
void main() {
Fruits* fruits[6];
fruits[0] = new Fruits();
// delete[] fruits[0]; // <-- does not work (deletes one object)
// delete[] fruits; // <-- does not work (deletes all objects in the array)
}
How can I do this?
delete fruits[0] will delete that one object for you. delete[] instead serves to delete all non-null elements of that array, but fruits[0] is not an array of objects.
You can't remove an item of an array using standard C++ arrays. Use std::vector instead.
An array like initialized with new[] is a buffer which pointer points at its first memory cell. In vectors and lists, elements are linked. Each element therefore points at its previous and next item, making it easy to remove or insert items. For this purpose, it requires more memory, though.
Example
// constructing vectors
#include <iostream>
#include <vector>
int main ()
{
// constructors used in the same order as described above:
std::vector<int> first; // empty vector of ints
std::vector<int> second (4,100); // four ints with value 100
std::vector<int> third (second.begin(),second.end()); // iterating through second
std::vector<int> fourth (third); // a copy of third
// the iterator constructor can also be used to construct from arrays:
int myints[] = {16,2,77,29};
std::vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );
std::cout << "The contents of fifth are:";
for (std::vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
And just for clarification,
delete fruits[0]
will delete the fruit that is located at the 0th element of the array, but it will not remove it from the array or make the array one element shorter.
You cannot delete what wasn't allocated with new and you can't mix new [] and delete nor new and delete [].
Firstly, you need dynamically allocated space for the elements, no necessarily array of pointers. Removal of an element can be done by shifting all the following elements, so the next element takes the place of the removed element, leaving an unused element at the end of the array, then possibly shrinking the allocated space.
This is practically implemented with std::vector and you shouldn't be implementing it yourself as a beginner. If you're seeking this functionality, use std::vector!
Related
As the title describes, I am trying to pass the pointer to the data of a std::vector into a function expecting a double pointer. Take as an example the code below. I have an int pointer d which is passed to myfunc1 as &d (still not sure if call it the pointer's reference or what), where the function changes its reference to the beginning of an int array filled with 1,2,3,4. However, if I have a std::vector of ints and try to pass &(vec.data()) to myfunc1 the compiler throws the error lvalue required as unary ‘&’ operand. I have already tried something like (int *)&(vec.data()) as per this answer, but it does not work.
Just for reference, I know I can do something like myfunc2 where I directly pass the vector as reference and the job is done. But I want to know if it's possible to use myfunc1 with the std::vector's pointer.
Any help will be very much appreciated.
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::vector;
void myfunc1(int** ptr)
{
int* values = new int[4];
// Fill all the with data
for(auto& i:{0,1,2,3})
{
values[i] = i+1;
}
*ptr = values;
}
void myfunc2(vector<int> &vec)
{
int* values = new int[4];
// Fill all the with data
for(auto& i:{0,1,2,3})
{
values[i] = i+1;
}
vec.assign(values,values+4);
delete values;
}
int main()
{
// Create int pointer
int* d;
// This works. Reference of d pointing to the array
myfunc1(&d);
// Print values
for(auto& i:{0,1,2,3})
{
cout << d[i] << " ";
}
cout << endl;
// Creates the vector
vector<int> vec;
// This works. Data pointer of std::vector pointing to the array
myfunc2(vec);
// Print values
for (const auto &element : vec) cout << element << " ";
cout << endl;
// This does not work
vector<int> vec2;
vec2.resize(4);
myfunc1(&(vec2.data()));
// Print values
for (const auto &element : vec2) cout << element << " ";
cout << endl;
return 0;
}
EDIT: What my actual code does is to read some binary files from disk, and load parts of the buffer into the vector. I was having troubles getting the modified vector out of a read function, and this is what I came up with that allowed me to solve it.
When you write:
myfunc1(&(vec2.data()));
You are getting the address of a rvalue. The pointed int* is so a temporary that is destroyed right after the call.
This is why you get this error.
But, as #molbdnilo said, in your myfunc1() function, you are reassigning the pointer (without caring to destroy previously allocated memory by the way).
But the std::vector already manages its data memory on its own. You cannot and you must not put your hands on it.
What my actual code does is to read some binary files from disk, and load parts of the buffer into the vector.
A solution could be to construct your std::vector by passing the iterator to the beginning and the iterator to the end of the desired part to extract in the constructor's parameters.
For example:
int * buffer = readAll("path/to/my/file"); // Let's assume the readAll() function exists for this example
// If you want to extract from element 5 to element 9 of the buffer
std::vector<int> vec(buffer+5, buffer+9);
If the std::vector already exists, you can use the assign() member function as you already did in myfunc2():
vec.assign(buffer+5, buffer+9);
Of course in both cases, you have to ensure that you are not trying to access an out of bounds element when accessing the buffer.
The problem is that you cannot take the address of data(), since it is only a temporary copy of the pointer, so writing to a pointer to it makes not that much sense. And that is good that way. You DO NOT want to pass data() to this function since it would overwrite the pointer with a new array and that would break the vector. You can remove one * from the function and only assign to it and not allocate the memory there. This will work, but make sure to allocate the memory in the caller (with resize, just reserve will result un undefined behavior, since data() is only a pointer to the beginning of the valid range [data(), data() + size()). The range [data(), data() + capacity ()) is not necessary valid.
I was wondering if in this case I could use the std::vector::resize() function instead of the erase(). I was wondering in the following case whether the ::erase() and ::resize() would do the same thing:
struct Foo
{
int* a = new int[10];
~Foo() { delete[] a; }
};
int main()
{
std::vector<Foo*> fooVector;
// FILL VECTOR WITH 100 FOO OBJECT POINTERS
int i = 100;
while (--i) fooVector.push_back(new Foo);
// DELETE LAST 50 FOO OBJECTS
for (int i = 50; i < 100; ++i)
delete fooVector[i];
// ERASE LAST 50 VECTOR ELEMENTS (POINTERS)
fooVector.erase(fooVector.begin() + 50, fooVector.end());
// IS THE LAST LINE THE SAME AS
fooVector.resize(50);
}
I was wondering, seeing as though the last 50 elements of vector are dangling pointers, would ::erase() and ::resize() do the same thing essentially? I'm guessing that ::resize() would do ::erase() for all old elements after the position of the last element before the ::resize().
Yes, erasing the last elements of a vector is equivalent to resizing it.
In both cases the last 50 elements are removed and the vector now has size 50.
I have the following struct:
#include <string>
#include <vector>
struct A {
std::string name;
int id;
};
And a vector containing A elements:
std::vector<A> a_vector;
I am trying to append an element to the vector and change its values using the following:
void test()
{
A a;
get_a(a);
//Up to this point I thought modifying this a object would mean modifying the back element of the vector. But it doesn't work as planned, doing this:
a.id = 2; //Doesn't modify the id of the element in the vector.
}
where get_a is defined as : (The code is simplified, in the real one I really need to pass a as argument and not get it as return)
void get_a(A& a) //This function normally assigns a in different ways
{
a_vector.emplace_back();
a = a_vector.back();
}
How can I do to have the a element be the same as the one in the vector? Do I really have to use pointers?
A a;
a = a_vector.back();
Here you're copy-assigning a_vector.back() to a. This is not a reference, so modifying a will not modify the element inside the vector.
You want this instead:
A& a = a_vector.back();
If you cannot immediately initialize your reference with a_vector.back(), consider using a pointer...
A* a;
// ...
a = &a_vector.back();
// ...
something(*a);
...or an index:
std::size_t a_idx;
// ...
a_idx = a_vector.size() - 1;
// ...
something(a_vector[a_idx]);
The pointer will work fine if you know that the vector won't get resized. If the vector resize, iterators and pointers will be invalidated.
The index will work fine even if the vector gets resized, as long as the elements are not removed/shifted around.
You need a reference to the object:
auto& a = a_vector.back();
Or, in a more compact manner:
a_vector.back().id = 2;
You're holding a copy, not the original object. That is why the object in vector does not get modified.
Answer to edited question: references can be assigned only during declaration. What you want is probably std::reference_wrapper, but anyway, please don't use it unless you have to.
I'm trying to create a class which maintains a fixed size vector of unique pointers to managed objects, like so:
std::vector<std::unique_ptr<Myclass>> myVector;
The vector gets initialized like so:
myVector.resize(MAX_OBJECTS,nullptr);
Now, what I need to to, is to be able to, on request, remove one of the stored unique pointers without affecting the size of the vector.
I also need to safely add elements to the vector too, without using push_back or emplace_back.
Thanks in advance.
Edit: I want the vector to be of constant size because I want to be able to add and remove elements in constant time.
If you want a vector of fixed size, use std::array.
To remove a unique_ptr in an index, you can use std::unique_ptr::reset():
myVector[i].reset()
To add an element to a specific index (overwriting what was there before) you can use std::unique_ptr::reset() with the new pointer as parameter:
myVector[i].reset(new Myptr(myparameter));
Reading a reference may also help:
http://en.cppreference.com/w/cpp/memory/unique_ptr
http://en.cppreference.com/w/cpp/container/array
http://en.cppreference.com/w/cpp/container/vector
Looks like you want to use a std::array<> rather than forcing std::vector<> to behave like one.
As already pointed out you should use std::array if the size is fixed.
E.g like this:
std::array<std::unique_ptr<YourType>, MAX_OBJECTS> myVector;
You can then remove or add a new pointer like this.
for(auto& v : myVector)
if(v && predicate)
v.reset();// or v.reset(ptr) to set a new one
You can use STL algorithm std::remove, like this:
// all items that should be removed will be the range between removeAt and end(myVector)
auto removeAt = std::remove_if(begin(myVector), end(myVector),
ShouldRemovePredicate);
// reset all items that should be removed to be nullptr
for(auto it = removeAt; it != end(myVector); ++it)
it->reset();
In addition, if the size is known at compile-time I would suggest using std::array<unique_ptr<MyObject>, SIZE> instead of a vector. However, if SIZE is not known at compile-time your code is ok.
You could use std::array instead of a std::vector since you know the number of the elements beforehand and you could add and remove elements like the following example:
#include <iostream>
#include <memory>
#include <array>
class foo {
std::size_t id;
public:
foo() : id(0) {}
foo(std::size_t const _id) : id(_id) {}
std::size_t getid() const { return id; }
};
auto main() ->int {
// construct an array of 3 positions with `nullptr`s
std::array<std::unique_ptr<foo>, 3> arr;
// fill positions
std::unique_ptr<foo> p1(new foo(1));
arr[0] = std::move(p1);
std::unique_ptr<foo> p2(new foo(2));
arr[1] = std::move(p2);
std::unique_ptr<foo> p3(new foo(3));
arr[2] = std::move(p3);
// print array
for(auto &i : arr) if(i != nullptr) std::cout << i->getid() << " ";
std::cout << std::endl;
// reset first position (i.e., remove element at position 0)
arr[0].reset();
// print array
for(auto &i : arr) if(i != nullptr) std::cout << i->getid() << " ";
std::cout << std::endl;
return 0;
}
LIVE DEMO
I'm trying to create an array of classes using a vector, but I think I'm getting the syntax wrong from instantiating the array. The error I'm getting is:
error: request for member 'setX' in objects[0], which is of non-class type 'std::vector'
#include <iostream>
#include <vector>
using std::cout;
class A {
public:
void setX(int a) { x = a; }
int getX() { return x; }
private:
int x;
};
int main() {
std::vector<A> *objects[1];
objects[0].setX(5);
objects[1].setX(6);
cout << "object[0].getX() = " << objects[0].getX() << "\nobject[1].getX() = " << objects[1].getX() << std::endl;
}
std::vector<A> objects; // declare a vector of objects of type A
objects.push_back(A()); // add one object of type A to that vector
objects[0].setX(5); // call method on the first element of the vector
With an asterisk and a square brackets, you are declaring an array of pointers to vectors instead of a vector. With std::vector<T> you do not need square brackets or an asterisk:
std::vector<A> objects(2); // 2 is the number of elements; Valid indexes are 0..1, 2 is excluded
objects[0].setX(5); // This will work
objects[1].setX(6);
The reason the compiler thought that you were trying to call setX on a vector is that the square bracket operator, overloaded by the vector, is also a valid operator on an array or a pointer.
An array and std::vector are two completely different container types. An array is actually a fixed-size block of memory, where-as a std:vector object is a dynamic sequential container type, meaning it can be dynamically "grown" and "shrunk" at run-time, and the object itself manages the memory allocation of the objects it owns. Their apparent similarities are that both can access members in O(1) complexity and can use the bracket syntax for accessing members.
What you want is something like the following:
int main()
{
//make a call to the std::vector<T> cstor to create a vector that contains
//two objects of type A
std::vector<A> objects(2);
//you can now access those objects in the std::vector through bracket-syntax
objects[0].setX(5);
objects[1].setX(6);
cout << "object[0].getX() = " << objects[0].getX() << "\nobject[1].getX() = " << objects[1].getX() << std::endl;
return 0;
}
here what you did is define an array with 1 element of type std::vector*, you may want to read more about vector and array first.
The correct way to define it is:
std::vector<A> objects(2);
or using pointers if that is what you intend to
std::vector<A*> objects(2);
objects[0] = new A();
objects[1] = new A();