Using a dynamic array inside a class -- Receiving error at compile time
QUESTION ANSWERED IN COMMENTS Because of my reputation, I can't answer it in the regular fashion. I'll add details in an answer later, already addressed in comments. Thanks.**
Hello all -
As you'll no doubt see based on the question, I'm new to C++, but have experience with some higher level languages. (Which seems to be hurting more than helping)
For a class, I need to create a wrapper for an Array that is typed to integers. (No templates at this stage of class) I also need to allow the class to have a non-zero starting index. I'm using a member array in the class to store my data (no vectors yet at this point of the class) and doing some translation from the public methods to access the appropriate internal array element.
The problem that I'm running into is that I don't know the internal array size at compile time, so I'm declaring it as a class global pointer and setting up the size in the constructor. A code snippet is below in the problem area:
int *list;
safeArray::safeArray(int start, int initialSize)
{
if(initialSize <= 0)
{
throw "Array size must be a positive integer";
}
maxSize = initialSize + 1;
startIndex = start;
endIndex = start + initialSize;
list = new int[maxSize]; // Error thrown here
int *tempArray = new int[maxSize];
copyArray(tempArray);
clearArray();
}
The error I'm getting is
Incompatible types in assignment of 'int*' to 'int[0u]'
I'm not 100% sure what the type of int[0u] is. Is that the literal value zero and the u is for unsigned? I've checked in the debugger that maxSize holds a value and I've also replaced it with a constant integer value and got the same error.
Because my int *tempArray = new int[maxSize];
line worked, I thought it might have something to do with needing to declare and size at the same time, so I opted to do a memcpy. (Which is actually outside the scope of the assignment, so there must be something else I'm missing) The memcpy fails because it appears that I'm clobbering my other variables. When I print the address of list in GDB, it gives me the same address as another global variable in my code, so that route also seemed it was out of the scope of the assignment.
The common theme I've seen in other forums is that you can't assign arrays like other variables, but I didn't think that would include the new
statement. Am I wrong in that assumption?
The only compilation errors I'm currently seeing is the one stated above, and I see it for every list = new int[maxSize];
statement in the code.
My questions are:
What is the type int[0u] and where is that type being generated? It would have to be from the new statement right?
What is the best way to utilize a dynamic array resource inside of a class? Besides using a vector? =)
I think that's all the relevant info, but my apologies if I missed a crucial piece of data. Below is the rest of the implementation code.
/*
* safeArray.cpp
* safearray
*
* Created by Jeffery Smith on 6/1/11.
*
*
*/
#include "safeArray.h"
#include <iostream>
using namespace std;
int startIndex = 0;
int endIndex = 0;
int maxSize = 1;
int currentSize = 0;
int *list;
safeArray::safeArray(int start, int initialSize)
{
if(initialSize <= 0)
{
throw "Array size must be a positive integer";
}
maxSize = initialSize + 1;
startIndex = start;
endIndex = start + initialSize;
list = new int[maxSize]; // Error thrown here
int *tempArray = new int[initialSize + 1];
copyArray(tempArray);
clearArray();
}
safeArray::safeArray(const safeArray &sArray)
{
list = new int[sArray.maxSize];
copyArray(sArray);
startIndex = sArray.startIndex;
endIndex = sArray.endIndex;
maxSize = sArray.maxSize;
currentSize = sArray.currentSize;
}
void safeArray::operator=(const safeArray &right)
{
list = new int[right.maxSize];
copyArray(right);
startIndex = right.startIndex;
endIndex = right.endIndex;
maxSize = right.maxSize;
currentSize = right.currentSize;
}
safeArray::~safeArray()
{
delete [] list;
}
int safeArray::operator[](int index)
{
if(OutofBounds(index))
{
throw "You tried to access an element that is out of bounds";
}
return list[index - startIndex];
}
void safeArray::add(int value)
{
if(this->isFull())
{
throw "Could not add element. The Array is full";
}
currentSize++;
list[currentSize + startIndex];
}
void safeArray::removeAt(int value)
{
if(OutofBounds(value))
{
throw "The requested element is not valid in this list";
}
compressList(value);
currentSize--;
}
void safeArray::insertAt(int location, int value)
{
if(OutofBounds(location) || this->isFull())
{
throw "The requested value is either out of bounds or the list is full";
}
expandList(location, value);
currentSize++;
}
void safeArray::clearList()
{
clearArray();
}
bool safeArray::isFull()
{
return(maxSize == currentSize);
}
int safeArray::length()
{
return currentSize;
}
int safeArray::maxLength()
{
return this->maxSize;
}
bool safeArray::isEmpty()
{
return(currentSize == 0);
}
bool safeArray::OutofBounds(int value)
{
return (value > endIndex || value < startIndex);
}
void safeArray::clearArray()
{
for(int i = 0; i < maxSize; i++)
{
list[i] = 0;
}
currentSize = 0;
}
void safeArray::compressList(int value)
{
for(int i = value; i < endIndex; i++)
{
list[i] = list[i + 1];
}
}
void safeArray::expandList(int location, int value)
{
int tempHolder = list[location];
list[location] = value;
for(int i = location; i < endIndex; i++)
{
tempHolder = list[location];
list[location] = value;
value = tempHolder;
}
}
void safeArray::copyArray(int *srcAddr )
{
memcpy(list, srcAddr, sizeof(int) * maxSize);
}
void safeArray::copyArray(const safeArray &sArray)
{
memcpy(list, &sArray, sizeof(int) * maxSize);
}
Here is the header definition:
/*
* safeArray.h
* safearray
*
* Created by Jeffery Smith on 6/1/11.
* Copyright 2011 Accenture. All rights reserved.
*
*/
class safeArray {
public:
safeArray(int,int); //Standard constructor
~safeArray(); //Destructor
int operator[](int);
void operator=(const safeArray&); //Assignment overload
safeArray(const safeArray &sArray); //Copy Constructor
void add(int);
int maxLength();
int length();
bool isFull();
bool isEmpty();
void clearList();
void removeAt(int);
void insertAt(int,int);
protected:
int list[];
int startIndex;
int endIndex;
int maxSize;
int currentSize;
private:
void clearArray();
bool OutofBounds(int);
void expandList(int,int);
void compressList(int);
void copyArray(int*);
void copyArray(const safeArray&);
};
开发者_开发百科
int[0u]
? I believe that you can, in C, have zero-length arrays at the end of structures to permit the use of variable-sized structures, effectively, but this is not done in C++. I don't see anything in your code that would be illegal code. Terrible, yes, illegal, no. You need to post the contents of safearray.h
, if it includes Standard headers, then your use of using namespace std;
could easily be the cause of the problem.
Also, global variables are bad. Just put the pointer inside the class- you should basically never have to use global variables unless you're doing something very wrong. Especially as it, say, leaves you open to variable shadowing, names clashes, and other, massive, problems. Oh, and you should throw an exception class, preferably derived from std::exception
or std::runtime_error
. Nobody will try to catch a const char*
. You shouldn't use the std
namespace- you're begging for problems. And you're not invoking the copy constructor or assignment operator, but using memcpy to copy your elements? You've also leaked memory in several places- starting with the assignment operator.
template<typename T> class safe_array {
char* list;
std::size_t arrsize;
void valid_or_throw(std::size_t index) {
if (index <= arrsize) {
throw std::runtime_error("Attempted to access outside the bounds of the array.");
}
public:
safe_array(std::size_t newsize)
: list(NULL) {
size = arrsize;
list = new char[arrsize];
for(std::size_t i = 0; i < arrsize; i++) {
new (&list[i * sizeof(T)]) T();
}
}
safe_array(const safe_array& ref)
: list(NULL) {
*this = ref;
}
safe_array& operator=(const safe_array& ref) {
clear();
arrsize = ref.size;
list = new char[arrsize];
for(std::size_t i = 0; i < arrsize; i++) {
new (&list[i * sizeof(T)]) T(ref[i]);
}
}
T& operator[](std::size_t index) {
valid_or_throw(index);
return static_cast<T&>(list[index * sizeof(T)]);
}
const T& operator[](std::size_t index) {
valid_or_throw(index);
return static_cast<const T&>(list[index * sizeof(T)]);
}
void clear() {
if (list == NULL)
return;
for(std::size_t i = 0; i < size; i++) {
(*this)[i].~T();
}
delete[] list;
list = NULL;
arrsize = 0;
}
std::size_t size() {
return arrsize;
}
bool empty() {
return (list == NULL);
}
~safe_array() {
clear();
}
};
A relatively quick sample class I whipped up that should point you more in the general direction. It doesn't offer all the functionality of a vector
, no automatic resizing for example or capacity buffering (and a few other shortcomings) and I'm quite confident I probably forgot a couple things, but it's a start.
@Bo helped me out in the comments. Turns out I had an old int list[] declaration in my header file that I never changed. So that compiler error it was throwing was due to the declaration there. After that everything was gravy.
精彩评论