initialing stl collection elements (not pointers) when no default constructor? - c++

I have such private field:
private:
std::vector<OneItemIndex> oneItemIndexes;
My class declared this way, there are no default constructor:
public OneItemIndex(int instrumentId)
I want my field to contain 10 elements like this:
oneItemIndexes
0 OneItemIndex(0)
1 OneItemIndex(1)
...
10 OneItemIndex(10)
How can I do this? What should I write in constructor? Is it possible?
Or I have to use OneItemIndex* instead of OneItemIndex and call new OneItemIndex(instrumentId myself this way?
IndexesStorage::IndexesStorage(void)
{
for (int i = 0; i < 10; i++) {
oneItemIndexes.push_back(new OneItemIndex(i));
}
}
Note: actually I dont' have hardcoded 10 elements, i'm using dynamic Instrument::InstrumentsCount()

In C++11 and later, you can initialise container elements by passing constructor arguments to an emplace function:
oneItemIndexes.emplace_back(i);
Historically, you could copy-initialise them (as long as they're copyable; but that was a requirement for vector before C++11):
oneItemIndexes.push_back(OneItemIndex(i));

I don't understand the leap to dynamic allocation in the middle of your question. Why do you think you suddenly have to use dynamic allocation and store pointers?
Use your loop, but with normal, automatic-storage-duration objects. oneItemIndexes.push_back(OneItemIndex(i)) or even oneItemIndexes.emplace(i).

You could use std::generate. Sorry for brevity of my answer but I am on my phone.

If you really don't want to make your object default-constructible and copyable, the easiest way to solve this would be to use a vector of shared_ptrs to OneItemIndex. This way you get the copy/initialize semantics vector requires from shared_ptr, but you don't need to have them on OneItemIndex itself (a raw pointer would work too, but then you need to take care of deleting the elements somewhere).

Adding my code which works so far. I'm not sure how stable this code and how safe to use such hacks. To avoid calling copy-construct I have to call reserve
IndexesStorage::IndexesStorage(void)
{
oneItemIndexes.reserve(Instrument::InstrumentsCount());
for (int i = 0; i < Instrument::InstrumentsCount(); i++) {
oneItemIndexes.emplace_back(i);
}
}
OneItemIndex::OneItemIndex(OneItemIndex& rhs):
CustomIndex("blabla")
{
printf("OneItemIndex copy-construct must not be called, we make it public cause MSVC++ implementation!");
exit(0);
}

Related

I need to optimize a function, which uses unique_ptr and shared_ptr

So, I have been working on my assignment for quite a while but stumbled upon a problem that I couldn't solve by myself.
My task was to create a class CompositeShape which would be capable of holding shared_ptr pointers of a base class Shape in a unique_ptr array so that we would then have an array of derived from Shape classes. The CompositeShape by itself is derived from Shape as well.
So, even though the code below works fine and even provides a strong exception guarantee, my teacher says that this particular function can be optimized.
void kosnitskiy::CompositeShape::add(const std::shared_ptr<Shape> &src)
{
if (src == nullptr)
{
throw std::invalid_argument("Attempt to add an empty pointer exception");
}
std::unique_ptr<std::shared_ptr<Shape>[]> shapes(new std::shared_ptr<Shape>[count_ + 1]);
for (int i = 0; i < count_; i++)
{
shapes[i] = std::move(shapes_[i]);
}
shapes[count_] = src;
shapes_ = std::move(shapes);
count_ += 1;
}
My first reaction was to change the array expanding algorithm to something similar to a vector one so that we wouldn't be forced to create a new array every time a new element is being added, but the teacher said, that despite the fact it's a quite good idea, he talks about the different type of improvement. The one, which wouldn't change the class design. So I assume there is a flaw somewhere in a function itself. I have already changed the assignment construction, used in a for loop, from shapes[i] = shapes_[i] to a one using the std::move instead, since I figured that move assignment operator would be way more efficient than a copy assignment one, but I'm pretty much out of ideas now.
I'm not allowed to make any class design changes. I didn't use vector because it was specified by the teacher that we can't use any standard containers. I didn't use weak_ptr for the same reason as well: we were told only to use unique_ptr and shared_ptr pointers. Non-smart pointers are blocked as well
Thank you very much for your help in advance
My guess is, that teacher's remark might about passing src by value and moving it into the array.
Another option would be to use std::move with std::begin/end instead of a raw for loop.
But both of those seem to be micro-optimizations with the array growing by 1 and being reallocated with each addition and are out of context.

push_back() changes size of other vector in function

I'm making a class which has a function that concatenates two vectors of unique_ptrs. When I use the push_back function, the size of the parameter vector changes, and I don't know why.
class A: public vector<unique_ptr<int>>{
public:
A& concatenate(A& c);
};
A& A::concatenate(A& c) {
for(int i = 0; i < c.size(); i++) { //this loop never stops
push_back(make_unique<int>()); //this line changes the size of c?
(*this)[(*this).size() - 1] = move(c[i]);
}
return *this;
}
The for loop doesn't stop running because every time the push_back method is used, the size of c is also incremented by 1.
I also thought to use resize() before the for loop, and then move all the pointers, but I want to know why the push_back method changes another vector.
That might happen when this A and the c A objects are same, i.e. you are trying to call concatenate on an object and passing the same object as param to concatenate.
So actually push_back is not changing size of another vector. Its the same vector you are working on.
On a sidenote, there are few issues with your code and post
As #PaulMcKenzie said, you should post an MCVE
In general, its not a good idea to derive from STL containers
Unless you are trying to learn how to implement, you should first try to find and use methods provided by STL containers. e.g. insert as suggested by
#Some programmer dude.

How do I initialize a vector member of a struct?

Suppose I have a struct with a member that is a vector. In the constructor, I want to just set it to NULL. But then later I want to be able to push_back things to it. How do I initialize the vector after it's NULL?
struct structName {
vector<int> vec;
structName() {
vec = NULL
}
void set(int);
}
void structName::set(int n) {
// What do I put here?
vec.push_back(n);
}
Thanks for the help!
It's already initialized via the default constructor and, if you need to call a different constructor, use an initialization list.
Remember, this is C++, not Java/C#/whatever. It makes no sense for an object to be null (ok, it doesn't in those languages either, but read on). It can't happen. In Java and languages like it you have variables which are references to objects and those references (not objects!) may or may not be null.
That is not the case in C++. There is a strict delineation between objects and pointers which refer to them (and pointers, or course, can be null or refer to an invalid memory location).
The default constructor for the vector will set it to its simplest state: no contents. So just leave it alone.
I think you be thinking of C++ objects like you would in Java. DON'T They are totally different beasts.
In C++, objects aren't references as in Java, thus, nulling them out doesn't make sense. In fact trying vec = NULL is an error as NULL is really just 0.
Instead just remove the line vec = NULL and it'll work as is. The vector will be default constructed as empty and you don't have to do any other initialization.
Initializing a vector to NULL doesn't make any sense. Perhaps you're getting confused with pointers. If you want to initialize your vector to the empty vector then that happens automatically. Like this in other words
struct structName {
vector<int> vec;
structName() {
}
void set(int);
}
void structName::set(int n) {
vec.push_back(n);
}

How to insert objects in a vector efficiently and correctly

Suppose I want to declare a vector of objects. I can do it this way -
vector<mynode> nodes;
But if the size of the mynode is large, this would be bad. So I think of doing it this way -
vector<mynode*> nodes;
But the above declaration has an obvious problem that I'm storing addresses and it's not safe at all. For instance, if i add objects in a foor loop -
vector<mynode*> nodes;
for (int i=0; i<10; i++)
{
mynode mn;
nodes.push_back(&mn);
}
This will lead to errors as I can never guarantee if the contents of the pointer are actually ok.
So, I decide to use this declaration -
vector<mynode&> nodes;
for (int i=0; i<10; i++)
{
mynode mn;
nodes.push_back(mn);
}
is this ok? safe? It gives a compilation with the first line itself. Please suggest some efficient way of storing the objects in a vector. thanks a lot.
I can do it this way -
vector<mynode> nodes;
But if the size of the mynode is large, this would be bad.
No, it would not. You need to store the objects anyway. If you are worried about copying large objects, you have some solutions:
Use std::vector<std::unique_ptr<my_node>> (or another smart pointer), which automatically releases objects on destruction. This is the best solution if my_node is polymorphic.
Use std::vector<my_node> and use the emplace_back function to construct objects in place (beware if you're using visual studio 2010, this function does not do what it is supposed to do).
Still use std::vector<my_node> and use push_back with a rvalue reference, as in
v.push_back(std::move(some_node));
to move already constructed objects.
Anyway, a good rule of thumb is to have the copy constructor/assignment deleted (or private) for most non-lightweight objects. Containers are still functional (provided, again, that you use C++11) and your concerns are moot.
Using references gives is essentially the same as using pointers (it's just that you don't need to dereference them in code).
If you want to automatically ensure that the objects inserted to vector don't get deleted without copying them, you should use smart pointers from boost or c++11.
vector< smart_ptr<mynode> > nodes;
for (int i=0; i<10; i++)
{
smart_ptr<mynode> mn = new mynode();
nodes.push_back(mn);
}
I dont see pointer being so bad here. It's not void or something. Inserting reference as in your example saves a reference to a temporary object located on a stack an this will go out of scope...

C++ New vs Malloc for dynamic memory array of Objects

I have a class Bullet that takes several arguments for its construction. However, I am using a dynamic memory array to store them. I am using C++ so i want to conform to it's standard by using the new operator to allocate the memory. The problem is that the new operator is asking for the constructor arguments when I'm allocating the array, which I don't have at that time. I can accomplish this using malloc to get the right size then fill in form there, but that's not what i want to use :) any ideas?
pBulletArray = (Bullet*) malloc(iBulletArraySize * sizeof(Bullet)); // Works
pBulletArray = new Bullet[iBulletArraySize]; // Requires constructor arguments
Thanks.
You can't.
And if you truly want to conform to C++ standards, you should use std::vector.
FYI, it would probably be even more expensive than what you're trying to achieve. If you could do this, new would call a constructor. But since you'll modify the object later on anyway, the initial construction is useless.
1) std::vector
A std::vector really is the proper C++ way to do this.
std::vector<Bullet> bullets;
bullets.reserve(10); // allocate memory for bullets without constructing any
bullets.push_back(Bullet(10.2,"Bang")); // put a Bullet in the vector.
bullets.emplace_back(10.2,"Bang"); // (C++11 only) construct a Bullet in the vector without copying.
2) new [] operator
It is also possible to do this with new, but you really shouldn't. Manually managing resources with new/delete is an advanced task, similar to template meta-programming in that it's best left to library builders, who'll use these features to build efficient, high level libraries for you. In fact to do this correctly you'll basically be implementing the internals of std::vector.
When you use the new operator to allocate an array, every element in the array is default initialized. Your code could work if you added a default constructor to Bullet:
class Bullet {
public:
Bullet() {} // default constructor
Bullet(double,std::string const &) {}
};
std::unique_ptr<Bullet[]> b = new Bullet[10]; // default construct 10 bullets
Then, when you have the real data for a Bullet you can assign it to one of the elements of the array:
b[3] = Bullet(20.3,"Bang");
Note the use of unique_ptr to ensure that proper clean-up occurs, and that it's exception safe. Doing these things manually is difficult and error prone.
3) operator new
The new operator initializes its objects in addition to allocating space for them. If you want to simply allocate space, you can use operator new.
std::unique_ptr<Bullet,void(*)(Bullet*)> bullets(
static_cast<Bullet*>(::operator new(10 * sizeof(Bullet))),
[](Bullet *b){::operator delete(b);});
(Note that the unique_ptr ensures that the storage will be deallocated but no more. Specifically, if we construct any objects in this storage we have to manually destruct them and do so in an exception safe way.)
bullets now points to storage sufficient for an array of Bullets. You can construct an array in this storage:
new (bullets.get()) Bullet[10];
However the array construction again uses default initialization for each element, which we're trying to avoid.
AFAIK C++ doesn't specify any well defined method of constructing an array without constructing the elements. I imagine this is largely because doing so would be a no-op for most (all?) C++ implementations. So while the following is technically undefined, in practice it's pretty well defined.
bool constructed[10] = {}; // a place to mark which elements are constructed
// construct some elements of the array
for(int i=0;i<10;i+=2) {
try {
// pretend bullets points to the first element of a valid array. Otherwise 'bullets.get()+i' is undefined
new (bullets.get()+i) Bullet(10.2,"Bang");
constructed = true;
} catch(...) {}
}
That will construct elements of the array without using the default constructor. You don't have to construct every element, just the ones you want to use. However when destroying the elements you have to remember to destroy only the elements that were constructed.
// destruct the elements of the array that we constructed before
for(int i=0;i<10;++i) {
if(constructed[i]) {
bullets[i].~Bullet();
}
}
// unique_ptr destructor will take care of deallocating the storage
The above is a pretty simple case. Making non-trivial uses of this method exception safe without wrapping it all up in a class is more difficult. Wrapping it up in a class basically amounts to implementing std::vector.
4) std::vector
So just use std::vector.
It's possible to do what you want -- search for "operator new" if you really want to know how. But it's almost certainly a bad idea. Instead, use std::vector, which will take care of all the annoying details for you. You can use std::vector::reserve to allocate all the memory you'll use ahead of time.
Bullet** pBulletArray = new Bullet*[iBulletArraySize];
Then populate pBulletArray:
for(int i = 0; i < iBulletArraySize; i++)
{
pBulletArray[i] = new Bullet(arg0, arg1);
}
Just don't forget to free the memory using delete afterwards.
The way C++ new normally works is allocating the memory for the class instance and then calling the constructor for that instance. You basically have already allocated the memory for your instances.
You can call only the constructor for the first instance like this:
new((void*)pBulletArray) Bullet(int foo);
Calling the constructor of the second one would look like this (and so on)
new((void*)pBulletArray+1) Bullet(int bar);
if the Bullet constructor takes an int.
If what you're really after here is just fast allocation/deallocation, then you should look into "memory pools." I'd recommend using boost's implementation, rather than trying to roll your own. In particular, you would probably want to use an "object_pool".