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);
}
Related
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);
}
I want to ask whether there are some problems with the copy for the vector of pointer items. Do I need to strcpy or memcpy because there may be depth copy problem?
For instance:
Class B;
Class A
{
....
private:
std::vector<B*> bvec;
public:
void setB(std::vector<B*>& value)
{
this->bvec = value;
}
};
void main()
{
....
std::vector<const B*> value; // and already has values
A a;
a.setB(value);
}
This example only assign the value to the class variable bvec inside A class. Do I need to use memcpy since I found that std::vector bvec; has pointer items? I am confused with the depth copy in C++, could you make me clear about that? Thank you.
Think about this, if you remove and delete an item from the vector value after you call setB, then the vector in A will have a pointer that is no longer valid.
So either you need to do a "deep copy", have guarantees that the above scenario will never happen, or use shared smart pointers like std::shared_ptr instead of raw pointers. If you need pointers, I would recommend the last.
There is another alternative, and that is to store the vector in A as a reference to the real vector. However, this has other problems, like the real vector needs to be valid through the lifetime of the object. But here too you can use smart pointers, and allocate the vector dynamically.
It is unlikely you need strcpy or memcpy to solve your problem. However, I'm not sure what your problem is.
I will try to explain copying as it relates to std::vector.
When you assign bvev to value in setB you are making a deep copy. This means all of the elements in the vector are copied from value to bvec. If you have a vector of objects, each object is copied. If you have a vector of pointers, each pointer is copied.
Another option is to simply copy the pointer to the vector if you wish to reference the elements later on. Just be careful to manage the lifetimes properly!
I hope that helps!
You probably want to define your copy constructor for class A to ensure the problem your asking about is handled correctly (though not by using memcpy or strcpy). Always follow the rule of three here. I'm pretty sure with std::vector your good, but if not, then use a for loop instead of memcpy
I am aware you cannot use an initialiser list for an array. However I have heard of ways that you can set an array of pointers to NULL in a way that is similar to an initialiser list.
I am not certain how this is done. I have heard that a pointer is set to NULL by default, though I do not know if this is guaranteed/ in the C++ standard. I am also not sure if initialising through the new operator compared to normal allocation can make a difference too.
Edit: I mean to do this in a header file/constructor initialisation list. I do not want to put it in the constructor, and I do not want to use a Vector.
In order to set an array of pointers to nulls in constructor initializer list, you can use the () initializer
struct S {
int *a[100];
S() : a() {
// `a` contains null pointers
}
};
Unfortunately, in the current version of the language the () initializer is the only initializer that you can use with an array member in the constructor initializer list. But apparently this is what you need in your case.
The () has the same effect on arrays allocated with new[]
int **a = new int*[100]();
// `a[i]` contains null pointers
In other contexts you can use the {} aggregate initializer to achieve the same effect
int *a[100] = {};
// `a` contains null pointers
Note that there's absolutely no need to squeeze a 0 or a NULL between the {}. The empty pair of {} will do just fine.
Normally an array will not be initialised by default, but if you initialise one or more elements explicitly then any remaining elements will be automatically initialised to 0. Since 0 and NULL are equivalent you can therefore initialise an array of pointers to NULL like this:
float * foo[42] = { NULL }; // init array of pointers to NULL
You can switch from array to std::vector and use
std::vector<T*> v(SIZE);
The values will be initialized by NULLs automatically. This is the preferred C++ way.
Update: Since C++11, there is one more way: using
std::array<T*, SIZE> array = {};
This behaves more like a corrected version of C-style array (in particular, avoids dynamic allocations), carries its size around and doesn't decay to a pointer. The size, however, needs to be known at compile time.
I am not certain how this is done. I have heard that a pointer is set to NULL by default, though I do not know if this is guaranteed/ in the C++ standard.
It is not guaranteed by the C++ standard. Built in types ( like pointers ) are filled with garbage unless set otherwise.
I am also not sure if initialising through the new operator compared to normal allocation can make a difference too.
What do you mean by "normal allocation" ? If you're talking about an automatic variable, then you can do this:
MyType * pointers[2] = {}
and the pointers should be initialized to NULL.
void* p[10] = { 0 };
If you have a member array then there is no way to initialize, unless it's a static member. If the array isn't a static member then you'll have to fill it inside the constructor's body.
That said, chances are you're really better off using a std::vector. Other than for technical reasons such as unavailability of a standard STL for your platform, or the slightly lesser performance a std::vector is better than an array by any and all criteria. If performance is the issue then make sure you profiled and know by numbers that it is an issue.
If I create an object on the stack and push it into a list, then the object loses scope (outside of the for loop in the example below) will the object still exist in the list? If the list still holds the object, is that data now invalid/possibly corrupt?
Please let me know, and please explain the reasoning..
Thanks,
jbu
class SomeObject{
public:
AnotherObject x;
}
//And then...
void someMethod()
{
std::list<SomeObject> my_list;
for(int i = 0; i < SOME_NUMBER; i++)
{
SomeObject tmp;
my_list.push_back(tmp);
//after the for loop iteration, tmp loses scope
}
my_list.front(); //at this point will my_list be full of valid SomeObjects or will the SomeObjects no longer be valid, even if they still point to dirty data
}
EDIT: so what if it were a std::list<SomeObject*> my_list; instead of list...in that case would it be invalid?
The standard containers make a copy of the object so the list is still ok in your example.
All containers make a copy of what they store. It's a requirement that an object be copy-constructible and assignable, if it is to be used in a container.
So yes, vector, list, etc. all make a copy of your object.
An even shorter example:
struct foo {};
std::vector<foo> v;
v.push_back(foo());
// makes a copy of the temporary, which dies at the semicolon.
If it didn't make a copy, the above code would be bad.
The following code is not ok:
struct foo {};
std::vector<foo*> v;
{
foo f;
v.push_back(&f); // fine, but...
} // ...now f stops existing and...
v.front(); // ...points to a non-existent object.
Yes, it's valid. push_back makes a copy.
With all STL containers (lists, vectors, maps, everything), the containers make a copy of what you add to the containers so, so long as what you add isn't a pointer or reference, you're safe.
If you write your own containers though, you have to be careful how you do things, since there's nothing stopping you from writing a type of container that stores references -- it would just be a nasty surprise to anyone that thought it worked like a standard container.
Yesterday I read some code of a colleague and came across this:
class a_class
{
public:
a_class() {...}
int some_method(int some_param) {...}
int value_1;
int value_2;
float value_3;
std::vector<some_other_class*> even_more_values;
/* and so on */
}
a_class a_instances[10];
void some_function()
{
do_stuff();
do_more_stuff();
memset(a_instances, 0, 10 * sizeof(a_class)); // <===== WTF?
}
Is that legal (the WTF line, not the public attributes)? To me it smells really, really bad...
The code ran fine when compiled with VC8, but it throws an "unexpected exception" when compiled with VC9 when calling a_instances[0].event_more_values.push_back(whatever), but when accessing any of the other members. Any insights?
EDIT: Changed the memset from memset(&a_instances... to memset(a_instances.... Thanks for pointing it out Eduard.
EDIT2: Removed the ctor's return type. Thanks litb.
Conclusion: Thanks folks, you confirmed my suspicion.
This is a widely accepted method for initialization for C structs.
In C++ it doesn't work ofcourse because you can't assume anything about vectors internal structure. Zeroing it out is very likely to leave it in an illegal state which is why your program crashes.
He uses memset on a non-POD class type. It's invalid, because C++ only allows it for the simplest cases: Where a class doesn't have a user declared constructor, destructor, no virtual functions and several more restrictions. An array of objects of it won't change that fact.
If he removes the vector he is fine with using memset on it though. One note though. Even if it isn't C++, it might still be valid for his compiler - because if the Standard says something has undefined behavior, implementations can do everything they want - including blessing such behavior and saying what happens. In his case, what happens is probably that you apply memset on it, and it would silently clear out any members of the vector. Possible pointers in it, that would point to the allocated memory, will now just contain zero, without it knowing that.
You can recommend him to clear it out using something like this:
...
for(size_t i=0; i < 10; i++)
objects[i].clear();
And write clear using something like:
void clear() {
a_object o;
o.swap(*this);
}
Swapping would just swap the vector of o with the one of *this, and clear out the other variables. Swapping a vector is especially cheap. He of course needs to write a swap function then, that swaps the vector (even_more_values.swap(that.even_more_values)) and the other variables.
I am not sure, but I think the memset would erase internal data of the vector.
When zeroing out a_instances, you also zero out the std_vector within. Which probably allocates a buffer when constructed. Now, when you try to push_back, it sees the pointer to the buffer being NULL (or some other internal member) so it throws an exception.
It's not legitimate if you ask. That's because you can't overload writing via pointers as you can overload assignment operators.
The worst part of it is that if the vector had anything in it, that memory is now lost because the constructor wasn't called.
NEVER over-write a C++ object. EVER. If it was a derived object (and I don't know the specifics of std::vector), this code also over-writes the object's vtable making it crashy as well as corrupted.
Whoever wrote this doesn't understand what objects are and needs you to explain what they are and how they work so that they don't make this kind of mistake in the future.
You shouldn't do memset on C++ objects, because it doesn't call the proper constructor or destructor.
Specifically in this case, the destructor of even_more_values member of all a_instances's elements is not called.
Actually, at least with the members that you listed (before /* and so on */), you don't need to call memset or create any special destructor or clear() function. All these members are deleted automatically by the default destructor.
You should implement a method 'clear' in your class
void clear()
{
value1=0;
value2=0;
value_3=0f;
even_more_values.clear();
}
What you have here might not crash, but it probably won't do what you want either! Zeroing out the vector won't call the destructor for each a_class instance. It will also overwrite the internal data for a_class.even_more_values (so if your push_back() is after the memset() you are likely to get an access violation).
I would do two things differently:
Use std::vector for your storage both in a_class and in some_function().
Write a destructor for a_class that cleans up properly
If you do this, the storage will be managed for you by the compiler automatically.
For instance:
class a_class
{
public:
a_class() {...}
~a_class() { /* make sure that even_more_values gets cleaned up properly */ }
int some_method(int some_param) {...}
int value_1;
int value_2;
float value_3;
std::vector<some_other_class*> even_more_values;
/* and so on */
}
void some_function()
{
std::vector<a_class> a_instances( 10 );
// Pass a_instances into these functions by reference rather than by using
// a global. This is re-entrant and more likely to be thread-safe.
do_stuff( a_instances );
do_more_stuff( a_instances );
// a_instances will be cleaned up automatically here. This also allows you some
// weak exception safety.
}
Remember that if even_more_values contains pointers to other objects, you will need to delete those objects in the destructor of a_class. If possible, even_more_values should contain the objects themselves rather than pointers to those objects (that way you may not have to write a destructor for a_class, the one the compiler provides for you may be sufficient).