I am having a strange issue with a CAtlArray. It works as expected if I use the Add function to add an element to the array. However, if I use SetCount before adding any elements, the program crashes. Strangely, it only works if I add elements directly with the [] operator (I know I know, the documentation says to only use [] to get an element, not to set one). I have been checking that SetCount returns true and it does.
Unfortunately, I can't get much debug info easily because this is a dll hooking another process. I can only debug by printing ...
I am wondering if this is typical behavior/if I am missing something (the documentation sucks, google did not return any helpful results, and the ATL code is hard for me to read/follow). My first thought was that SetCount(X) might have some behavior like calling Add() X times and shouldn't be called unless it is expanding the array, but SetAt doesn't work with SetCount either.
Any ideas about what might be going on here?
EDIT:
CAtlArray<MyClass*> arr;
...
size_t initialCount = 10;
if ( arr.SetCount(initialCount) ) {
for ( int i = 0; i < initialCount; i++ ) {
//arr.Add( new MyClass );//Does NOT work
//arr.SetAt( i, new MyClass );//Does NOT work
arr[i] = new MyClass;//This works
}
}
EDIT 2:
I forgot to mention, I also tried using the GetData method but it didn't work either:
MyClass **pData;
if ( arr.SetCount(initialCount) ) {
pData = arr.GetData();
for ( int i = 0; i < initialCount; i++, pData++ ) {
*pData = new MyClass;
}
}
All the three attempts to add elements DO work, but they don't do exactly the same thing, and - more important - the dangerous option does not crash the application and only creates a condition that causes crash later.
//arr.Add( new MyClass );//Does NOT work
//arr.SetAt( i, new MyClass );//Does NOT work
arr[i] = new MyClass;//This works
Let's see what the they actually do:
SetCount adds 10 NULL elements to the array
following Add leaves those ten nulls and adds your instances as 11th, 12th and on
following SetAt replaces NULLs with your instances
following indexed set replaces NULLs with your instances in the same way as #2 above
So items #2 and #3 do "work" and item #1 does a different thing: the array has 20 items and if you later attempt to access the elements, you hit NULLs where you expect to have valid pointers.
Have a look at small application that prints element count (you can see you have 10 or 20 elements), and then does element checking to verify if all elements of the array are "valid".
#include "stdafx.h"
#include <atlcoll.h>
class MyClass
{
private:
INT m_nValue;
public:
MyClass() :
m_nValue(0xDEADC0DE)
{
}
VOID Check()
{
ATLASSERT(m_nValue == 0xDEADC0DE);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
CAtlArray<MyClass*> arr;
size_t initialCount = 10;
if(arr.SetCount(initialCount))
{
for( int i = 0; i < initialCount; i++ )
{
arr.Add( new MyClass );//Does NOT work
//arr.SetAt( i, new MyClass );//Does NOT work
//arr[i] = new MyClass; //This works
}
}
_tprintf(_T("arr.GetCount() %d\n"), arr.GetCount());
for(SIZE_T nIndex = 0; nIndex < arr.GetCount(); nIndex++)
arr[nIndex]->Check();
return 0;
}
An easier way to put elements to the array is as follows:
size_t initialCount = 10;
//if(arr.SetCount(initialCount)) -- not needed
{
for( int i = 0; i < initialCount; i++ )
{
arr.Add( new MyClass );
}
}
Related
So I am just trying to make an array of objects of my custom class bcLED and I am getting the error.
error: no match for 'operator=' (operand types are 'bcLed' and 'bcLed*')
Can some one tell me why? I know it will be something simple.
also why i am here is there a way to create an array of an unspecified length in C++ and then just append it with an new row each time I want to add an object to it?
void PopulateLEDS(){
int i;
bcLed ledArr[17];
for (i = 0; i< 16; i++)
{
ledArr[i] = new bcLed();
ledArr[i].id = i;
ledArr[i].charge = 0;
}
}
OK so i need more help
To avoided creating ten thousand posts I am going to paste the main body of the code so that to see where I am tripping up with the C++ syntax.
the lattest errors are
/Users/bencawley/Documents/Arduino/Test/Bens_Lights/Bens_Lights.ino: In function 'void PopulateLEDS()':
Bens_Lights:49: error: expected primary-expression before 'public'
public:bcLed ledArr[17];
^
Bens_Lights:52: error: 'ledArr' was not declared in this scope
ledArr[i].id = i;
^
/Users/bencawley/Documents/Arduino/Test/Bens_Lights/Bens_Lights.ino: In function 'void BensPattern(uint8_t)':
Bens_Lights:69: error: 'ledArr' was not declared in this scope
strip.setPixelColor(i,0, 0, ledArr[i].charge, 0);
^
Using library Adafruit_NeoPixel at version 1.0.6 in folder: /Users/bencawley/Documents/Arduino/libraries/Adafruit_NeoPixel
exit status 1
expected primary-expression before 'public'
And my code is:
class bcLed{
public:int id;
public:int charge;
void incCharge(int amt)
{
charge = charge+amt;
if(charge >= 255){charge = 255;}
}
};
void setup() {
strip.begin();
strip.show(); // Initialize all pixels to 'off'
PopulateLEDS();
}
void loop() {
// Some example procedures showing how to display to the pixels:
BensPattern(45);
}
void PopulateLEDS(){
int i;
bcLed ledArr[17];
for (i = 0; i< 17; i++)
{
ledArr[i].id = i;
ledArr[i].charge = 0;
}
}
void BensPattern(uint8_t wait)
{
uint16_t i, j;
int rn = rand() % strip.numPixels() ;
for (i = 0; i<strip.numPixels(); i++)
{
strip.setPixelColor(i,0, 0, 0, 0);
}
for (i = 0; i<rn; i++)
{
strip.setPixelColor(i,0, 0, ledArr[i].charge, 0);
ledArr[i].incCharge(1);
}
strip.show();
delay(wait);
}
new isn't always needed in C++, and definitely not here. new allocates dynamic memory for you if automatic allocation isn't good enough for you. You usually only use new if you want the variable to outlive it's scope. Memory allocated with new must also always be deleted in order to avoid a memory leak. In modern C++, the use of new is even less needed because we have smart pointers.
bcLed ledArr[17];
This already creates 17 bcLeds for you (like how you would use new in C#, requires no cleanup), no need to use new on them. Just work with them.. Your loop condition is wrong too, it's supposed to be < 17.
for (i = 0; i < 17; i++)
{
ledArr[i].id = i;
ledArr[i].charge = 0;
}
also why i am here is there a way to create an array of an unspecified
length in C++ and then just append it with an new row each time I want
to add an object to it?
Yes, that's what a std::vector is for:
#include <vector>
std::vector<bcLed> ledArr(17);
//loop over them:
for(int i = 0; i < ledArr.size(); ++i)
{
//ledArr[i]
}
//or:
for(std::vector<bcLed>::iterator itr = ledArr.begin() itr != ledArr.end(); ++itr)
{
//*itr
}
// to insert to the back of the vector use push_back:
bcLed aLed;
ledArr.push_back(aLed);
If you have access to C++11 you can use a range based loop instead and use emplace_back:
#include <vector>
std::vector<bcLed> ledArr(17);
//loop over them, just to iterate:
for(const auto& led : ledArr)
{
//led.id
//led.charge
}
//appending to the vector:
ledArr.emplace_back(/*constructor arguments*/);
To answer your comment
ok im going to brave and ask this when you say "if you want the
variable to outlive it's scope or you're working with low level
memory" I don't understand what any of that means... well mostly I
don't understand what you mean by scope or low level memory. Could you
explain those? is scope the time that the method runs for?
A scope of a variable is the context in which it is defined. Automatic storage lives until the end of it's scope. Braces { } indicate scope. For example:
void foo()
{
int x;
bcLed aLed;
{ //create a new inner scope
bcLed innerLed;
} //scope ends, all automatic variables are destroyed (innerLed in this case)
//can't use `innerLed` here.
int new_int = x;
} // scope ends, same goes, new_int, x, aLed are destroyed.
Really though, a good book will tell you the differences and when they should be used.
ledArr[i] = new bcLed(); doesn't work, as the error message said, you can't assign an pointer to bcLed (i.e. bcLed*) to a bcLed.
For bcLed ledArr[17];, the 17 elements of array has been default constructed; You don't need to new one at all. So just remove the code causing errors, the following code would work fine.
bcLed ledArr[17];
for (i = 0; i < 16; i++)
{
ledArr[i].id = i;
ledArr[i].charge = 0;
}
is there a way to create an array of an unspecified length in C++ and then just append it with an new row each time I want to add an object to it?
That's what std::vector supposed to do.
If you want to process all the elements of the array, the condition of for should be i < 17.
Well, I have a class which is supposed to be a container for quadratic polynomials (which is a template and I'm using floats there, but that shouldn't matter much). I made it using a dynamic array, and I was supposed to overload + and - operators... Not a problem, eh? Well, it seemed all nice and dandy until I actually run it.
listf listf::operator+(listf rhs)
{
listf newlist;
for(int i = 0; i < elementcount; ++i)
newlist.add(array[i]);
for(int j = 0; j < rhs.elementcount; ++j)
newlist.add(rhs.array[j]);
std::cout<<newlist;
return newlist;
}
Nothing much. Should do its job correctly, right? That cout is just to check if it works. But it does not.
Should do something like this, right?
With one list consisting of:
X^2+5x+52.4
2X^2+7x-12
and the second one having just X^2+2X+1, it should make a list and display:
X^2+5x+52.4
2X^2+7x-12
X^2+2X+1
Buuuut no, it comes to this:
-1.5584e+038X^2-1.5584e+038x-1.5584e+038
-1.5584e+038X^2-1.5584e+038x-1.5584e+038
-1.5584e+038X^2-1.5584e+038x-1.5584e+038
I've been battling with it for quite some time and have not found why it would do that.
Code for adding new polynomials is still quite simple:
void listf::add(polynomial<float> plnm)
{
if(array == NULL)
{
++elementcount;
array = new polynomial<float>[elementcount];
array[0] = plnm;
}
else
{
array = resize(array, elementcount+1, elementcount);
array[elementcount++] = plnm;
}
}
And resize is a private function in this class:
polynomial<float>* listf::resize(polynomial<float>* arr, int newSize, int oldSize)
{
polynomial<float>* newArr = new polynomial<float>[newSize];
for(int i = 0; i < oldSize; ++i)
{
newArr[i] = arr[i];
}
delete[] arr;
return newArr;
}
If we're making a smaller array (for deleting objects), I just put oldSize equal to newSize (I know it's a bad practice and confusing for others, but I was just testing things :( )
I'm out of ideas. Adding new elements to an object seems working, but when I want to add two objects it breaks, prints elements that are not correct and then crashes with CodeLite reporting something like "ntdll!LdrVerifyImageMatchesChecksumEx" in Call Stack. Even better, when I tested it right now, it displayed correct values, but still crashed at return.
Forget the home-made dynamic array and use vector. Whenever you go into the realm of classes and memory management, it isn't as trivial as coding up a few new[] and delete[] calls. It can stop you dead in your tracks in the development of your program.
#include <vector>
//...
typedef std::vector<polynomial<float> > PolynomialFloatArray;
//...
class listf
{
PolynomialFloatArray array;
//...
void add(const polynomial<float>& plnm);
//...
PolynomialFloatArray& resize(PolynomialFloatArray& arr, int newSize)
};
//...
void listf::add(const polynomial<float>& plnm)
{
array.push_back(plnm);
}
PolynomialFloatArray& listf::resize(PolynomialFloatArray& arr, int newSize)
{
arr.resize(newSize);
return arr;
}
There in a nutshell is all of that code you wrote, reduced down to 2 or 3 lines.
Like the comments on the question point out, you would probably be better off using std::vector for this, as it has push_back() to add stuff to the end, and automatically resizes itself to do so, though you can force it to resize with resize().
As above, I'm trying to create and then fill an array of structures with some starting data to then write to/read from.
I'm still writing the cache simulator as per my previous question:
Any way to get rid of the null character at the end of an istream get?
Here's how I'm making the array:
struct cacheline
{
string data;
string tag;
bool valid;
bool dirty;
};
cacheline **AllocateDynamicArray( int nRows, int nCols)
{
cacheline **dynamicArray;
dynamicArray = new cacheline*[nRows];
for( int i = 0 ; i < nRows ; i++ )
dynamicArray[i] = new cacheline [nCols];
return dynamicArray;
}
I'm calling this from main:
cacheline **cache = AllocateDynamicArray(nooflines,noofways);
It seems to create the array ok, but when I try to fill it I get memory errors, here's how I'm trying to do it:
int fillcache(cacheline **cache, int cachesize, int cachelinelength, int ways)
{
for (int j = 0; j < ways; j++)
{
for (int i = 0; i < cachesize/(cachelinelength*4); i++)
{
cache[i][ways].data = "EMPTY";
cache[i][ways].tag = "";
cache[i][ways].valid = 0;
cache[i][ways].dirty = 0;
}
}
return(1);
}
Calling it with:
fillcache(cache, cachesize, cachelinelength, noofways);
Now, this is the first time I've really tried to use dynamic arrays, so it's entirely possible I'm doing that completely wrong, let alone when trying to make it 2d, any ideas would be greatly appreciated :)
Also, is there an easier way to do write to/read from the array? At the moment (I think) I'm having to pass lots of variables to and from functions, including the array (or a pointer to the array?) each time which doesn't seem efficient?
Something else I'm unsure of, when I pass the array (pointer?) and edit the array, when I go back out of the function, will the array still be edited?
Thanks
Edit:
Just noticed a monumentally stupid error, it should ofcourse be:
cache[i][j].data = "EMPTY";
You should find your happiness. You just need the time to check it out (:
The way to happiness
My program works but my professor says that my code is incorrect but stated that he will get to why in the fall term... What is he talking about?
perhaps something is improper? Even if you are incorrect I would appreciate picking your brain :)
void CResizableArray::SetSize( int intNewSize )
{
int intIndex = 0;
if( intNewSize < 0 ) intNewSize = 0;
if( intNewSize > intMAXIMUM_ARRAY_SIZE )
{
intNewSize = intMAXIMUM_ARRAY_SIZE;
}
//////////////////////////////////////
// ---> HUGE BUG HERE <--- //
// Code works but is WRONG //
// WHY IS THIS HELP ME FIND THE BUG //
//////////////////////////////////////
m_intArraySize = intNewSize;
m_paintValues = new int [m_intArraySize];
// Initialize to zero
for( intIndex = 0; intIndex < m_intArraySize; intIndex++ )
{
*( m_paintValues + intIndex ) = 0;
}
}
Presumably before this line
m_paintValues = new int [m_intArraySize];
m_paintValues pointed to another array. That array has now been leaked -- you don't have a pointer to it, so it can never be freed. That memory can therefore never be reused. Write a program that does a lot of this, and it'll run out of memory before running very long.
When you're through with a block of memory, you need to free it. Here, the proper thing to do might look something like
delete[] m_paintValues;
m_paintValues = new int [m_intArraySize];
There are more issues, though. First of all, you can never use delete[] unless you know that m_paintValues definitely points to an array; you could ensure that in the constructor. More troubling is that fact that when you set a new size, any data previously in m_paintValues is discarded -- don't you want to copy the old values into the new array? Doing so would mean using a temporary variable to hold the new array when first allocated, copying the data, and then assigning the new array to the member variable.
He may mean that since it is a resize you should keep the old contents of the array and transfer them over to the new array, in your snippet you just throw away the old content creating a new empty array.
so instead of
m_paintValues = new int [m_intArraySize];
// Initialize to zero
for( intIndex = 0; intIndex < m_intArraySize; intIndex++ )
{
*( m_paintValues + intIndex ) = 0;
}
do
int* newBiggerArray = new int[m_intArraySize];
for (intIndex = 0; intIndex < m_intArraySize; ++intSize)
{
if ( intIndex < oldMaxSize )
{
newBiggerArray[intIndex] = m_paintValues[intIndex];
}
else
{
newBiggerArray[intIndex] = 0;
}
}
delete [] m_paintValues;
m_paintValues = newBiggerArray;
I will leave the part to handle a resize to a smaller value than previous for you to figure out.
This feels like a newbie issue, but I can't seem to figure it out. I want to iterate over the items in a std::vector. Currently I use this loop:
for (unsigned int i = 0; i < buffer.size(); i++) {
myclass* var = buffer.at(i);
[...]
}
However, I realised that I actually want to iterate over it in the opposite order: starting at the end and working my way to 0. So I tried using this iterator:
for (unsigned int i = buffer.size()-1; i >= 0; i--) {
myclass* var = buffer.at(i);
[...]
}
But by simply replacing the old line with the new (and of course, recompiling), then it goes from running properly and iterating over the code, it instead causes the program to crash the first time it hits this line, with this error:
http://i43.tinypic.com/20sinlw.png
Followed by a "[Program] has stopped working" dialog box.
The program also returns exit code 3, according to Code::Blocks, which (if this article is to be believed) means ERROR_PATH_NOT_FOUND: The system cannot find the file specified.
Any advice? Am I just missing something in my for loop that's maybe causing some sort of memory issue? Is the return code of 3, or the article, misleading, and it doesn't actually mean "path not found"?
An unsigned integer is always >= 0. Furthermore, decrementing from 0 leaps to a large number.
When i == 0 (i.e. what should be the last iteration), the decrement i-- causes i to wrap around to the largest possible value for an unsigned int. Thus, the condition i >= 0 still holds, even though you'd like the loop to stop.
To fix this, you can try something like this, which maintains the original loop logic, but yields a decrementing i:
unsigned int i;
unsigned int size = buffer.size();
for (unsigned int j = 0; j < size; j++) {
i = size - j - 1;
Alternatively, since std::vector has rbegin and rend methods defined, you can use iterators:
for(typename std::vector<myclass *>::reverse_iterator i = buffer.rbegin(); i != rend(); ++i)
{
myclass* var = *i;
// ...
}
(There might be small syntactic errors - I don't have a compiler handy)
#include <vector>
using namespace std;
int main() {
vector<int> buffer = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (vector<int>::reverse_iterator it = buffer.rbegin(); it != buffer.rend(); it++) {
//do your stuff
}
return 0;
}