I have the following piece of code which after running throws error :
class arr2{
int count;
public:
int elem[5];
arr2()
{
count=-1;
elem[5]=(0,0,0,0,0); //{} throws error i dont know why
}
};
int main()
{
arr2 obj;
vector<int> vec;
vec.assign(10,42);
vector<int> ::iterator itr=vec.begin();
for(;itr!=vec.end();++itr){
cout<<*itr<<endl;
}
return 0;
}
ERROR stack around the variable 'obj' was corrupted.
If i remove arr2 obj; then it works fine.
Is there anything wrong with the class itself or the statement in ctor elem[5]=(0,0,0,0,0);
I tried to define an array in main with {} and it works fine. I dont know why it fails when inside class.
int arr4[4]={1,2,3,4}; //OK
int elem[5]; // Represents that the array is of size 5
Since array index starts with 0, the available array indices are:
elem[0]
elem[1]
elem[2]
elem[3]
elem[4]
(total five elements)
elem[5] is out of bounds.
You need to consider that there are two distinct constructs at work here.
Initialisation
// initialiser
// |
// name ("elem") |
// | |
// ▼▼▼▼ ▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼
int elem[5] = {0, 0, 0, 0, 0};
// ▲▲▲ ▲▲▲
// \ /
// \ /
// \ /
// type (int[5])
Assignment
// new element value
// |
// name ("elem") |
// | |
// ▼▼▼▼ ▼▼▼▼▼
elem[n] = 12345;
// ▲▲▲ ▲
// | |
// | assignment operator
// |
// index (n)
Your problem has nothing to do with whether you write your code in main or in a class definition; the problem is that you are trying to write an assignment as if it were an initialisation.
The initialiser {0, 0, 0, 0, 0} simply cannot be used in an assignment
When you write elem[5] instead of int elem[5], you're naming the 6th element of elem, not declaring a new array of size 5 called elem.
The error goes away when you use (0, 0, 0, 0, 0) instead, because this is an expression that evaluates to 0, and you can assign 0 to an element of an int array.
Unfortunately, you're doing so to an element that does not exist, because elem[5] is out of bounds. It's a hypothetical sixth element in a five-element array.
The inability to use initialiser syntax to assign to all of an array's elements in one fell swoop is a limitation of C and C++.
To assign to the array at an arbitrary place, you'd have to assign them one by one in a loop, or use a fill function:
std::fill(std::begin(elem), std::end(elem), 0);
…which is much better anyway.
Fortunately, you've committed another crime that's actually quite convenient: you actually do want to initialise, even though at the moment you're instead assigning inside the constructor body. To initialise class members, you must use the constructor's member-initialiser list and, as it happens, the constructor's member-initialiser list enables us to use initialiser syntax:
arr2()
: elem{0, 0, 0, 0, 0}
{}
…or, more simply:
arr2()
: elem{}
{}
The assignment
elem[5]=(0,0,0,0,0);
write a single zero (read about the comma operator) at the sixth place in the array (remember that array indexes are zero-based), which is one beyond the end of the array. Writing beyond the bounds of an array leads to undefined behavior.
There are a few ways to initialize the array, the simplest being a constructor initializer list:
class arr2
{
int elem[5];
public:
arr2()
: elem{}
{}
};
The above will value-initialize the array, which means that each element in the array also will be value-initialized, and for an int value-initialization will set it to 0.
To expand on the error you get, just about all systems and compilers today store local variables on the stack, that includes the variable obj in your main function. Placing an object on the stack also places its member variables on the stack. If you write out of bounds of the array, then you also write on stack-memory you do not own the right to, and therefore corrupt the stack.
This does not do what you expect:
elem[5]=(0,0,0,0,0);
You assign the element at index 5 (which is out of bounds) the value 0. You do not assign an initializer list, but rather a series of zeroes with the comma operator in between (which returns the second value of each call), which in turn returns the rightmost zero.
elem[5]=(0,0,0,0,0); //{} throws error i dont know why
using {} throws error because, {} have to be used only for initialization of array, not for assignment.
Also above statement is not assigning all your array elements to zero, instead it tries to assign one zero to elem[5], which is actually out of boundary of your array.
your array starts at elem[0] and ends at elem[4].
elem[5] is actually refers to the address of vector defined below.
vector vec;
As you are corrupting this memory. You got exception.
Related
This seems like a really basic thing to do, but anyway I couldn't manage to find a solution to it so far, because I always find only questions that are asking how to check if the vector is actually empty, which is not what I want to check for.
Consider this code example:
#include <iostream>
#include <vector>
using namespace std;
struct Atom {
int x,y;
int pol;
};
int main() {
vector<vector<Atom>> vec=vector<vector<Atom>>(5,vector<Atom>(5));
cout<<(vec[0][0]==nullptr); // this line doesn't compile, because the vector doesn't hold pointers.
return 0;
}
I'm trying to declare a vector of vectors of objects of a custom type. At the beginning of the Programm I will initialise the vector so that it has a specific size, but without assigning an actual object to it. Now I want to be able to check if I already assigned an object to a specific position of the vector. I would've liked to use something like vec==nullptr but this doesn't work, because the objects in the vector aren't pointers. Unfortunately I can't just change the structs standard constructor to put some indicator value that I can check for like Atom.pol==-2, because the class is created by ROS messages. Any other suggestions on how to check if I already assigned an object?
EDIT: pol will always be either -1 or 1 after I assigned an object. So is it safe to check Atom.pol==0? When I tried to do this on ideone.com it always worked, but I assume that it's not guaranteed to be 0, right?!
There is no way to check whether an object has been initialised. That said, elements of std::vector are always initialised, so there is never a need to check either.
It seems that you want to represent an "unassigned" object. The standard library has a template for you: std::optional. If you create a vector optional objects, those objects, when value-initialized, will be in "unassigned" state.
EDIT: pol will always be either -1 or 1 after I assigned an object. So is it safe to check Atom.pol==0?
Yes, that would be safe, since the constructor that you use initialises the elments using a value initialised argument.
If you can assume that some states of the object are "not valid", then you don't necessarily need to use std::optional. If the value initialised state is such invalid state, then you don't need to add a default constructor to the class either. Just like a value initialised pointer compares equal to nullptr, so too the integer members of the value initialised Atom compare equal to 0.
but I assume that it's not guaranteed to be 0, right?!
It is guaranteed to be 0.
The solution to use pol == 0 should be fine, provided that pol == 0 is in fact not a normal state for that object to be in and that you don't try it with an uninitialized instance.
The std::vector constructor you are using guaranties that the new elements are default inserted. If you are using the default allocator (which you are) then that performs value initialization of those new elements. Since Atom is a class type with a default constructor that is neither user-provided nor deleted, then your instance of Atom are zero initialized. That means each of Atom's members' value is initialized to zero.
Beware that this is something std::vector does. You need your Atoms to be initialized to zero for this approach to work. If you tried the following, it would be undefined behavior. The Atom members are not initialized, much less guaranteed to be zero :
int main()
{
Atom a;
std::cout << (a.pol == 0); // <- Not okay
}
You can force value initialization by adding {} though :
int main()
{
Atom a{};
std::cout << (a.pol == 0); // <- Okay now
}
Edit : Accidentally used the same code sample for both examples.
One way to do this is to change the signature of vec to,
vector<vector<Atom*>> vec=vector<vector<Atom*>>(5,vector<Atom*>(5));
Then you can do the null ptr check to see if a given element has been initialized. This does add some complexity though, as you have to handle the memory allocation yourself.
If you want to initialize the members of Atom to specific values and check if they are initialized, you can do this.
vector<vector<Atom>> vec=vector<vector<Atom>>(5,vector<Atom>(5, {1, 2, 3}));
This initializes x, y, pol to 1, 2 and 3 respectively.
Minimal Example:
int main() {
using std::cout;
using std::vector;
vector<vector<Atom>> vec=vector<vector<Atom>>(5,vector<Atom>(5, {1, 2, 3}));
cout<<((vec[0][0]).x == 1) << "\n";
cout<<((vec[0][0]).y == 2) << "\n";
cout<<((vec[0][0]).pol == 3) << "\n";
cout<<((vec[0][0]).x == -1) << "\n";
cout<<((vec[0][0]).y == -1) << "\n";
cout<<((vec[0][0]).pol == -1) << "\n";
return 0;
}
See Demo
so lets suppose i have this structure
struct CAddition {
int x;
int y;
int c;
int z[3];
int result() {
return x + y;
}
CAddition();
~CAddition();
};
CAddition::CAddition()
:x(0)
,y(2)
,z()
,c(result())
{
}
and now in the constructor I have initialized z which is an array member of the struct ,z() it output the initialized values with zeros , now when I try this other syntax
,z{}
and
,z{0,0,0}
they all output the same result
Is there a more efficient way to initialize an array in the constructor except the above two and is there any difference the 3 methods , I checked different websites for initialization they have used the either methods
If you want to initialize all elements in array with default value 0, using z{0} is very fast. Or if you want to initialize with the value -1, you can use memset() :
CAddition::CAddition()
:x(0)
,y(2)
,c(result())
{
memset(z, -1, 3 * sizeof(int));
}
Notice that, memset() works on bytes, not the number. If you need to fill array with a number , you can use fill_n() instead.
If by "more efficient way" you mean taking less time to construct CAddition, then no there isn't.
The fastest way to construct CAddition is to initialize the array to all zeros, which is the default behaviors.
It will take negligible amount of time for an array of 3 items, but it can take a long time if the size of the array is very large, in which case you'd be better off using std::vector and reserve some space instead.
I have a class Pixel and a class Image with a function used to update a pixel line. I want to initialize the pixel line. My problem is to initialize the vector. Actually I have this :
bool UpdateLine(std::vector<Pixel>& line, int nb)
{
bool noError = true;
line = new std::vector<Pixel>(nb);
// Do some stuff
return noError;
}
When I try this I have :
no viable overloaded '='
How can I initialize the vector ?
The expression you are using:
new std::vector<Pixel>(nb)
returns a pointer to std::vector<Pixel> (i.e.: std::vector<Pixel> *), and not a std::vector<Pixel>, which is what you need.
A distinction between initialization and assignment has to be done: you are assigning to line and not initializing it.
You can create a new vector and assign it to line by means of an assignment operator:
line = std::vector<Pixel>(nb);
What you do is assignment, not initialization.
Initializing a vector could be done like this:
std::vector<int> second (4,100); // four ints with value 100
In your case however, the vector is already declared outside of the function, so in that case you use vector::resize and do this:
line.resize(nb); // creates 'nb' objects 'Pixel'
PS: You don't need new keyword, except if you dynamically allocating memory for your vector.
I have a static integer variable Game::numPlayers, which is read in as an input from user. I then have the following class defined as such:
class GridNode
{
private:
/* Members */
static const int nPlayers = Game::numPlayers;
std::vector<Unit> units[nPlayers];
//...
};
This won't compile ("in-class initializer for static data member is not a constant expression").
I obviously cant just assign the array size of Game::numPlayers, and I also tried not initializing it and letting a constructor do the work, but that didn't work either.
I don't understand what I'm doing wrong here and what else I could possibly do to get this to work as intended.
I'm just copying a value, how is that any different from static const int nPlayers = 8 which copies the value 8 into nPlayers and works?
Edit:
To clarify, I choose to have an array of vectors because I want each node to have a quick-access container of units, but one container for each user/player so as to distinguish which units belong to which player within each node (e.g. index 0 of the array = player 1, index 1 = player 2, index 2 = player 3, and so on), otherwise I would just have one vector or a vector of vectors. I thought a map might work, but I thought an array of vectors would be faster to access and push into.
Also, Game::numPlayers is read in as a user input, but only read and assigned once within one game loop, but if I close/restart/play a new game, it needs to read in the user input again and assign it once.
I don't see why you need to use an array of std::vector if the number of elements will be obtained at runtime.
Instead, create a std::vector<std::vector<Units>> and size it appropriately on construction. if you need to reset the size, have a member function resize the vector.
Example:
class GridNode
{
private:
/* Members */
std::vector<std::vector<Unit>> units;
public:
GridNode(int nPlayers=10) : units(nPlayers) {}
std::vector<Unit>& get_units(size_t player)
{ return units[player]; } // gets the units for player n
void set_num_players(int nPlayers)
{ units.resize(nPlayers); } // set the number of players
int get_num_players() const { return units.size(); }
};
int main()
{
int numPlayers;
cin >> numPlayers;
//...
GridNode myGrid(numPlayers); // creates a GridNode with
// numPlayers vectors.
//...
Unit myUnit;
myGrid.get_units(0).push_back(myUnit); // places a Unit in the
// first player
}
Also, it isn't a good idea to have extraneous variables tell you the vector's size. The vector knows its own size already by calling the vector::size() function. Carrying around unnecessary variables that supposedly gives you this information opens yourself up for bugs.
Only integral constant expressions are allowed as array sizes in array declarations in C++. A const int object initailized with something that is not an integral constant expression (your Game::numPlayers is not, since it is read from the user), does not itself qualify as integral constant expression.
The bottom line here is that regardless of how you slice it, it is not possible to sneak in a run-time value into an array declaration in C++. C++11 does support some semblance of C99-style Variable Length Arrays, but your case (a member array) is not covered by it anyway.
If the array size is a run-tuime value, use std::vector. In your case that would become std::vector of std::vectors.
Suppose there is a structure such as:
struct XYZ
{
double a;
double b;
}
Now we make an object of it
struct XYZ abcd[10];
and now I am filling this array.
I have to initialize this array because I call this in a loop and it overwrites the previous values.
If it overwrites the previous 5 values by 4 new values then still the 5th one is still there in the array which results in the wrong output.
If you use c++ you can define a constructor, observe:
struct XYX {
double a, b;
XYX() { a=0; b=0; }
}
Initializing a struct is easily done by enumerating it's member values inside curly braces. Beware, though, 'cause if a member is omitted from the enumeration, it will be regarded as zero.
struct A { int a_, b_; };
A a = { 1, 2 };
A b = { 1 }; // will result in a_=1 and b_=0
A as [] = { {1,2}, {1,3}, {2,5} };
Strangely enough, this also works for the public members of an "aggregate" class. It's to be discouraged, though, since this way your class will lose it's ability to do the necessary things at construction time, effectively reducing it to a struct.
for (int i=0; i<10; ++i)
{
abcd[i].a = 0.0;
abcd[i].b = 0.0;
}
Of course, if some of the slots haven't been filled with meaningful data you probably shouldn't be looking at them in the first place.
If your question is how to initialize the array elements then #cemkalyoncu answer will help you.
If it over rites the previous 5 values
by 4 new values then still the 5th one
is still there in the array which in
result gives wrong output.
For this case it is better you go for vector.
You can remove the unwanted elements from the vector to make sure that it does not contain the wrong values.
In this case, remove 5th element from vector if you no longer use.
In addition to xtofl's answer, note, that if you want to zero-initialize the array, all you have to do is write
XYZ abcd[10] = {};
Also you can initialize with memset function
memset(&abcd[index], 0, sizeof(XYZ));