class Tool
{
public:
Tool();
~Tool();
private:
char **s;
};
char *s1[]={"hello","world"};
How can I initialize s and make it same as s1?
s={"hello","world"}
doesn't seem to work.
While you could use a std::vector<std::string>, I feel it's more beneficial to you to directly answer your question.
char** s is a pointer to a pointer; possibly a pointer to the first pointer in an array of pointers.
char* s1[] is an array of pointers to const data (and should have actually been made const).
If you want s to work similarly to s1, you first need to allocate the array of pointers, which is the reason std::vector was recommended by others. You could do it yourself with new, but you have to release the allocated memory at some point. Using new directly is prone to leaks. std::vector will release its allocated memory when the object is destructed. You too could call delete[] in your destructor if you wanted to.
When your array has been allocated, you then need to std::copy the array of pointers in s1 to the array of pointers in s. It's not a single assign operation.
Related
So assuming I have these private data members of a class in a .h file
private:
eventlist *pointer;
int counter;
int size;
and this struct type
struct eventlist// Define our struct type
{
char name[100];
char todo[100];
char where[100];
char when[100];
char attended[100];
char excitement[100];
};
And I want to create a dynamic array of structs. Here is what I have as a constructor...
summerlist::summerlist()
{
size = 0;// Initialize size to zero
counter = 0;//Initialize counter to zero
pointer = new eventlist[size];
strcpy(pointer[0].name,"\0");
strcpy(pointer[0].todo,"\0");
strcpy(pointer[0].where,"\0");
strcpy(pointer[0].when,"\0");
strcpy(pointer[0].attended,"\0");
strcpy(pointer[0].excitement,"\0");
}
I am mostly curious about:
Is it okay to allocate my array of structs in my constructor? Could it cause any problems?
Is it okay to allocate the array before initializing the pointer to NULL? I am assuming it is not a big deal since I am in a way initializing it as a pointer to a dynamic array. But I want to know if it is an acceptable practice.
Does it make sense to initialize the first element of the array like the way I did? I thought since the memory is allocated for at least one element of the array (the base) it'd be a good practice to initialize the first element, but I am still a little shaky whether I am visualizing correy.
Lastly, after I created my dynamic array and I set pointer to = NULL, that would just create a memory leak, and wouldn't initialize the first element right?
Yes this is fine, in fact allocating in the constructor and deleting in the destructor is the start of RAII types which you should aim to achieve.
You are simply assigning a pointer to some memory, it does not matter what the pointer held before, it could be anything.
That depends entirely on your application.
Yes you would. You need to delete any memory you have created. I would suggest in the destructor of your class. Remember to match new[] with delete[].
As a final note, this type of code is good for learning, but bad for implementation in c++. Unless you have some form of memory restriction (which you clearly don't since you are creating a big set of dynamic stored structures) then you should switch to using some of the built in c++ types, like std::vector to replace your dynamic array, and std::string to replace your char arrays.
struct eventlist {
std::string name;
...
}
class summerlist {
public:
summerlist();
private:
std::vector<eventlist> pointer;
int counter;
}
summerlist::summerlist()
{
counter = 0;// Initialize the counter to zero
}
This is much easier to use and control. And you avoid the mistake of doing this: pointer = new eventlist[size]; where size is 0. This should save you some headache.
For example i have class with constructor that has array of ints as parameter:
A(int* array) : m_array(array) {}
I can use it like this:
int array[] = { ... }
A a(array);
Or like this:
int* array = new int[10];
A a(array);
If object then use it array, it must (or may be not?) delete it in desctructor (if it was dynamic). But how he will know, that memory for this array was allocated dynamically?
You can't know if it's dynamically allocated or not, because after all, int* array is an int pointer, not an array. You might as well pass:
int i;
A a(&i);
As you can imagine, bad things will happen if you try to delete[] that one, or try to access m_array[N] with N > 0.
So you have to rely on the caller to do the right thing; there's nothing you can do to verify or enforce it. All you have is the address of an int. Who created that int, or how or whether more ints follow after it, will be unknown.
If you want more safety, use an std::vector. This is what it was made for.
You're initializing the array in the constructor, so it will always be initialized. It is pre-defined in the code that it will be allocated. If there are other constructors that do not allocate your array, you will need to do this check.
By the way, this is under the assumption that the array you are allocating is a member of the class. If you are assigning it to a new stack variable within the constructor, you won't be able to delete it in the destructor.
From what i understand you are trying to ask is whether the destructor will free the memory you have allocated to the array.
No, the memory you have allocated using new will have to be deleted by you either in the destructor or somewhere else the pointer is in scope as your memory allocation is not inside the constructor but outside.
You cannot know what it was because a static array decays into a pointer as well.
Basically you just need the value of the array passed to the constructor. You need not know whether it was a dynamically allocated or statically allocated array. What matters is the data member array which is part of the interface of your class and into which you are copying the data. Responsibility of the array passed to the constructor as an argument should rest with the caller regarding its deletion and lifetime.
It would make your life easier if you use std::vector instead of raw array.
In this Informit C++ guide, I read this:
Using malloc() to create a non–POD object causes undefined behavior:
//disastrous!
std::string *pstr =(std::string*)malloc(sizeof(std::string));
I didn't understand 2 points here :
Pointers are PODs. Then why it is called non-POD here? (Maybe I have to understand POD better.)
How can this be so disastrous? (I guess I have to understand string Internals for this.)
Please explain!
pointers are PODs then why here it is called non-POD
It's not talking about the pointer, but the std::string.
It's disastruous because malloc doesn't call the constructor, so you'll have pstr a std::string pointer that points to a std::string that wasn't properly constructed. The memory was allocated but it wasn't initialized properly, because of the missing constructor call.
The correct way is
std::string *pstr = new std::string;
The clean way is to just have a variable in automatic storage:
std::string str;
Here you are allocating a standard string, not allocating a pointer to a standard string. Note that you are passing sizeof(std::string) to malloc; that is how much memory you are getting back...note the size of the object is bigger than the size of a pointer. If you were only allocating a pointer, you'd expect the size passed in to be sizeof(std::string*).
The pointer you receive back is how you keep track of the result of the allocation, but that pointer isn't living on the heap. Here it's just being stored in an ordinary variable. Had you allocated a pointer instead, then your variable to keep track of it would need to be a pointer-to-a-pointer.
Anyway, if you wanted to, you could legally allocate a pointer to a standard string like this:
std::string str;
std::string** ptr_to_pstr = (std::string**)malloc(sizeof(std::string*);
*ptr_to_pstr = &str;
Why you would want to is not entirely clear. But neither is it clear why you'd use malloc in C++. :)
I'd need a class like std::auto_ptr for an array of unsigned char*, allocated with new[]. But auto_ptr only calls delete and not delete[], so i can't use it.
I also need to have a function which creates and returns the array. I came out with my own implementation within a class ArrayDeleter, which i use like in this example:
#include <Utils/ArrayDeleter.hxx>
typedef Utils::ArrayDeleter<unsigned char> Bytes;
void f()
{
// Create array with new
unsigned char* xBytes = new unsigned char[10];
// pass array to constructor of ArrayDeleter and
// wrap it into auto_ptr
return std::auto_ptr<Bytes>(new Bytes(xBytes));
}
...
// usage of return value
{
auto_ptr<Bytes> xBytes(f());
}// unsigned char* is destroyed with delete[] in destructor of ArrayDeleter
Is there a more elegant way to solve this? (Even using another "popular" library)
Boost has a variety of auto-pointers, including ones for arrays. Have you considered if std::vector is sufficient? Vectors are guaranteed to be contiguous in memory, and if you know the size and allocate memory ahead of time via reserve() or resize(), the location in memory will not change.
I then have to call a methods that takes unsigned char* as argument.
std::vector<unsigned char> vec;
.
.
.
legacy_function(&vec[0], vec.size());
How about using std::basic_string<unsigned char>? Or maybe std::vector<unsigned char>?
You're talking about an array of int, not complex C++ types that have a destructor.
For such an array calling delete[] is equivalent to calling delete. So there's no problem to use std::auto_ptr.
The method you suggest is very barbaric IMHO. You actually allocate memory twice: once for the needed array, and then you also allocate an instance of ArrayDeleter, which encapsulates the pointer to the allocated array.
The drawbacks of such a method are:
Worse performance. Heap operations are heavy. Also they have significant memory overhead.
Slower access. To access an element of your array via the std::auto_ptr<Bytes> the compiler will generate two indirections: one to get your Bytes object, and the other to access the element.
In simple words: std::auto_ptr has a pointer to Bytes object, which has a pointer to the array.
Worse error/exception consistency. Imagine what if the operator new fails to allocate the Bytes object. It'll generate an exception, which may be handled. But at this point you've already allocated the array. And this allocation will be lost.
I'd do one of the following:
If you're talking about an ordinary type - just use std::auto_ptr<type>. This should do the work. However you should check it with your compiler.
For complex types: you may create your own wrapper instead of the std::auto_ptr.
Another variant: similar to what you did. However you should get rid of the extra memory allocations and indirections.
I'm a bit confused about handling an array of objects in C++, as I can't seem to find information about how they are passed around (reference or value) and how they are stored in an array.
I would expect an array of objects to be an array of pointers to that object type, but I haven't found this written anywhere. Would they be pointers, or would the objects themselves be laid out in memory in an array?
In the example below, a custom class myClass holds a string (would this make it of variable size, or does the string object hold a pointer to a string and therefore take up a consistent amount of space. I try to create a dynamic array of myClass objects within a myContainer. In the myContainer.addObject() method I attempt to make a bigger array, copy all the objects into it along with a new object, then delete the old one. I'm not at all confident that I'm cleaning up my memory properly with my destructors - what improvements could I make in this area?
class myClass
{
private:
string myName;
unsigned short myAmount;
public:
myClass(string name, unsigned short amount)
{
myName = name;
myAmount = amount;
}
//Do I need a destructor here? I don't think so because I don't do any
// dynamic memory allocation within this class
};
class myContainer
{
int numObjects;
myClass * myObjects;
public:
myContainer()
{
numObjects = 0;
}
~myContainer()
{
//Is this sufficient?
//Or do I need to iterate through myObjects and delete each
// individually?
delete [] myObjects;
}
void addObject(string name, unsigned short amount)
{
myClass newObject = new myClass(name, amount);
myClass * tempObjects;
tempObjects = new myClass[numObjects+1];
for (int i=0; i<numObjects; i++)
tempObjects[i] = myObjects[i]);
tempObjects[numObjects] = newObject;
numObjects++;
delete newObject;
//Will this delete all my objects? I think it won't.
//I'm just trying to delete the old array, and have the new array hold
// all the objects plus the new object.
delete [] myObjects;
myObjects = tempObjects;
}
};
An array in C++ is an array of objects laid out in memory.
So for example in:
struct pair {
int x; int y;
};
...
pair array[10];
Each item in the array is going to be with a size of two ints.
If you want an array of pointers you can simply declare one:
pair* array_of_pointers[10];
The string objects have pointers to the variable size part of the string. So they're safe.
In fact they're the important lesson here. Same way you use the string class to avoid excessive memory handling you can use the vector class to avoid all the troubles of handling a dynamic array.
For the case you're doing this as an exercise. Here are a few problems:
newObject needs to be allocated locally, without new. This will make the code correct (as newObject is not a pointer and new returns a pointer) and will also save you the trouble of explicitly handling memory. (On a more advanced note, this makes the code exception safe in one more location)
myObject is never initialized. And you don't use initialization lists in the constructor. The constructor should look like this:
myContainer() : numObjects(0), myObjects(NULL)
{
}
The destructors in the code are exactly as they should be.
No, a dynamic array is not an array of pointers to that type - its a pointer to the first element. The elements are laid out consecutively in memory and are destroyed when the array is delete[]ed.
Thus your deallocation looks fine - you create dynamic arrays of myClass objects so you don't have to delete them individually. You would only have to do this if you had an array of pointers to (dynamically allocated) objects.
There are two definitive errors though:
tempObjects[numObjects] = newObject; // assign a myClass pointer to a myClass instance?
This should be e.g.:
tempObjects[numObjects] = myClass(name, amount);
Also, myObjects is never initialized, which means it contains garbage and dereferencing/using it leads to undefined behaviour.
Finally, unless you are doing this for learning purposes, simply use containers like std::vector that do all the work for you already.
I would expect an array of objects to be an array of pointers to that object type, but I haven't found this written anywhere. Would they be pointers, or would the objects themselves be laid out in memory in an array?
The array will consist of the objects themselves. If you want to have an array of pointer you will have to declare that:
myClass ** tempObjects;
tempObjects = new myClass*[numObjects+1];
I assume you are used to C# or Java? In those languages objects can only be allocated on heap and are always accessed by referenced. It is possible in C++, but in C++ you can also put objects directly on the stack, or directly construct an array of the objects themselves.
In the example below, a custom class myClass holds a string (would this make it of variable size, or does the string object hold a pointer to a string and therefore take up a consistent amount of space?
Number two: The string object itself is constant in size, but has a pointer to a dynamically sized buffer allocated from the heap.
I think the deallocation looks fine. The code could be written more efficient in various ways, but it looks correct.
Try to test it, to see what happens (yes, that may be compiler-specific, but still)...
You could try to add a custom destructor to myClass (even though you don't need one), that increments a "global" counter when called, Then print the counter after deleting the array.
I would expect the destructor of each object to be called. Note that quite often objects are stored "by-pointers" to allow for inherited objects to be put into the array (avoiding "slicing").