What is the exact behaviour of delete and delete[]? - c++

Why is this code wrong? Am I missing something regarding the behaviour of delete and delete[]?
void remove_stopwords(char** strings, int* length)
{
char** strings_new = new char*[*length];
int length_new = 0;
for(int i=0; i<*length; i++) {
if(is_common_keyword(strings[i]) == 0) {
strings_new[length_new] = strings[i];
length_new++;
}
else {
delete strings[i];
strings[i] = nullptr;
}
}
delete[] strings;
strings = new char*[length_new];
for(int i=0; i<length_new; i++) {
strings[i] = strings_new[i];
}
delete[] strings_new;
*length = length_new;
}
Explanations: this code should take an array of C-style strings and remove some particular strings of them; the array of C-style strings was created using new[] and every C-style string was created using new. The result of the code is that no word is canceled, but the array is only sliced.

I don't see any problem in the use of new[] or delete[] in the code shown.
No, wait.
I see a lot¹ of problems, but your intent is clear and the code seems doing what you want it to do.
The only logical problem I notice is that you're passing strings by value (it's a char** and reassigning it in the function will not affect the caller variable containing the pointer). Changing the signature to
void remove_stopwords(char**& strings, int* length)
so a reference is passed instead should fix it.
(1) Using std::vector<const char *> would seem more logical, even better an std::vector<std::string> if possible, that would take care of all allocations and deallocations.

every C-style string was created using new.
I suspect this is your problem -- C style strings are char arrays, so you can't readily create them with new, you need to use new[]. Which means you need to use delete[].

As #6502 pointed out, your basic problem is fairly simple: you're passing a char **, and attempting to modify it (not what it points at) in the function.
You're using that as a dynamically allocated array of strings, so what you're modifying is just the copy of the pointer that was passed into the function. Since you (apparently) want the function to modify what was passed into it, you need to either pass a char *** (ugh!) or char **& (still quite awful).
You really should use a vector<std::string> for the data. At least in my opinion, the code to remove the stop words should be written as a generic algorithm, something on this general order:
template <typename InIt, typename OutIt>
void remove_stop_words(InIt b, InIt e, OutIt d) {
std::remove_copy_if(b, e, d,
[](std:string const &s) { is_stop_word(s); });
}
With this, the calling code would look something like this:
// read input
std::vector<std::string> raw_input { std::istream_iterator<std::string>(infile),
std::istream_iterator<std::string>() };
// Filter out stop words:
std::vector<std::string> filtered_words;
remove_stop_words(raw_input.begin(), raw_input.end(),
std::back_inserter(filtered_words));
In a case like this, however, you don't really need to store the raw input words into a vector at all. You can pass an istream_iterator directly to remove_stop_words, and have it just produce the desired result:
std::ifstream in("raw_input.txt");
std::vector<std::string> filtered_words;
remove_stop_words(std::istream_iterator<std::string>(in),
std::istream_iterator<std::string>(),
std::back_inserter(filtered_words));
As an aside, you could also consider using a Boost filter_iterator instead. This would/will allow you to do the filtering in the iterator as you read the data rather than in an algorithm applied to the iterator.

Related

constructing char*const* from string

I am trying to convert a string to a const*char* in order to be able to call a library function. My code is as follows:
// myVec is simply a vector<string>
vector<string> myVec;
/* stuff added to myVec
* it is a vector of words that were seperated by whitespace
* for example myVec[0]=="Hey"; myVec[1]=="Buck"; myVec[2]=="Rogers"; etc...
*/
char*const* myT = new char*[500]; //I believe my problem stems from here
for(int z=0; z<myVec.size(); z++) {
string temp=myVec[z]+=" ";
myT[z]=temp.c_str();
}
//execv call here
I am constructing this for the second parameter of execv().
Compiler always throws various errors, and when I fix one another one pops up (seems rather circular from the solutions/google-fu I have employed).
The signature of execv expects the array of arguments to point to modifyable C style strings. So contrary to what the other answers suggest, c_str() is not such a good idea.
While not guaranteed in C++03, the fact is that all implementations of std::string that I know of store the data in a contiguous NULL terminated block of memory (this is guaranteed in C++11), so you can use that to your advantage: Create a vector of pointers to modifiable character arrays, initialize the values with the buffers for the strings in your input vector and pass the address of that block of data to execv:
std::vector<char*> args;
args.reserve(myVec.size()+1);
for (std::vector<std::string>::iterator it=myVec.begin(); it != myVec.end(); ++it) {
args.push_back(&((*it)[0]);
}
args.push_back(0); // remember the null termination:
execv("prog", &args[0]);
There are two fundamental problems which need addressing. The
first is a compiler error: the pointers in the array pointed to
by myT are const, so you cannot assign to them. Make myT
char const** myT;. The second problem is that what you are
assigning to them is a pointer into a local variable, which
will be destructed when it goes out of scope, so the pointers
will dangle.
Does the function you are calling really need the extra white
space at the end? (You mentioned execv somewhere, I think.
If that's the function, the extra whitespace will do more harm
than good.) If not, all you have to do is:
std::vector<char const*> myT( myVec.size() + 1 );
std::transform( myVec.begin(), myVec.end(), myT.begin(),
[]( std::string const& arg ) { return arg.c_str(); } );
execv( programPath, &myT[0] );
If you can't count on C++11 (which is still usually the case),
you can probably do something similar with boost::bind;
otherwise, just write the loop yourself.
If you do need to transform the strings in myVec in some way,
the best solution is still to copy them into a second
std::vector<std::string>, with the transformation, and use
this.
(BTW: do you really want to modify the contents of myVec, by
using += on each element in the loop?)

C++ Allocate Memory Without Activating Constructors

I'm reading in values from a file which I will store in memory as I read them in. I've read on here that the correct way to handle memory location in C++ is to always use new/delete, but if I do:
DataType* foo = new DataType[sizeof(DataType) * numDataTypes];
Then that's going to call the default constructor for each instance created, and I don't want that. I was going to do this:
DataType* foo;
char* tempBuffer=new char[sizeof(DataType) * numDataTypes];
foo=(DataType*) tempBuffer;
But I figured that would be something poo-poo'd for some kind of type-unsafeness. So what should I do?
And in researching for this question now I've seen that some people are saying arrays are bad and vectors are good. I was trying to use arrays more because I thought I was being a bad boy by filling my programs with (what I thought were) slower vectors. What should I be using???
Use vectors!!! Since you know the number of elements, make sure that you reserve the memory first (by calling myVector.reserve(numObjects) before you then insert the elements.).
By doing this, you will not call the default constructors of your class.
So use
std::vector<DataType> myVector; // does not reserve anything
...
myVector.reserve(numObjects); // tells vector to reserve memory
You can use ::operator new to allocate an arbitrarily sized hunk of memory.
DataType* foo = static_cast<DataType*>(::operator new(sizeof(DataType) * numDataTypes));
The main advantage of using ::operator new over malloc here is that it throws on failure and will integrate with any new_handlers etc. You'll need to clean up the memory with ::operator delete
::operator delete(foo);
Regular new Something will of course invoke the constructor, that's the point of new after all.
It is one thing to avoid extra constructions (e.g. default constructor) or to defer them for performance reasons, it is another to skip any constructor altogether. I get the impression you have code like
DataType dt;
read(fd, &dt, sizeof(dt));
If you're doing that, you're already throwing type safety out the window anyway.
Why are you trying to accomplish by not invoking the constructor?
You can allocate memory with new char[], call the constructor you want for each element in the array, and then everything will be type-safe. Read What are uses of the C++ construct "placement new"?
That's how std::vector works underneath, since it allocates a little extra memory for efficiency, but doesn't construct any objects in the extra memory until they're actually needed.
You should be using a vector. It will allow you to construct its contents one-by-one (via push_back or the like), which sounds like what you're wanting to do.
I think you shouldn't care about efficiency using vector if you will not insert new elements anywhere but at the end of the vector (since elements of vector are stored in a contiguous memory block).
vector<DataType> dataTypeVec(numDataTypes);
And as you've been told, your first line there contains a bug (no need to multiply by sizeof).
Building on what others have said, if you ran this program while piping in a text file of integers that would fill the data field of the below class, like:
./allocate < ints.txt
Then you can do:
#include <vector>
#include <iostream>
using namespace std;
class MyDataType {
public:
int dataField;
};
int main() {
const int TO_RESERVE = 10;
vector<MyDataType> everything;
everything.reserve( TO_RESERVE );
MyDataType temp;
while( cin >> temp.dataField ) {
everything.push_back( temp );
}
for( unsigned i = 0; i < everything.size(); i++ ) {
cout << everything[i].dataField;
if( i < everything.size() - 1 ) {
cout << ", ";
}
}
}
Which, for me with a list of 4 integers, gives:
5, 6, 2, 6

How can I pass an array by reference to a function in C++?

I have the following program where two variables are to be passed by reference to a function where their values will be determined based on external factors before being returned to main() so that they can be used by other functions. The first variable I am trying to pass is an int, and that goes fine, but the other is an array of strings, which is causing me some problems.
I've done enough research into this to know that you can't have an array or references (though I've yet to figure out why) and I was wondering if anyone could help me figure out how to do this? The various methods I've tried have all resulted in segmentation faults.
NB: The code below has the array being passed by value since I just don't know what to write for it.
Update: I'm required to use an array for my coursework. Some other data structure, such as the vector that has been suggested, would be great, but I have to use specific structures.
void initialise_existing_devices(int& no_of_existing_devices, string existing_devices[100]);
int main()
{
int no_of_existing_devices = 0;
string existing_devices[100];
initialise_existing_devices(no_of_existing_devices, existing_devices[100]);
}
void initialise_existing_devices(int& no_of_existing_devices, string existing_devices[100])
{
string line;
ifstream DeviceList;
DeviceList.open("devices/device_list");
while (true)
{
getline(DeviceList, line, '\n');
if (DeviceList.eof())
{
break;
}
++ no_of_existing_devices;
}
DeviceList.close();
DeviceList.open("devices/device_list");
for (int i = 0; i < no_of_existing_devices; i ++)
{
getline(DeviceList, line, '\n');
existing_devices[i] = line;
}
}
A reference to an array looks like:
void f(std::string (&a)[N]) { }
where a is the name of the parameter and N is the number of elements in the array.
However, usually in C++ you don't pass an array by reference (you can; it's just not common). Other options include:
Pass a pointer to the initial element of the array; in this case, consider passing the size of the array as a second argument to the function.
Use a std::vector<std::string> or a std::array<std::string, N> instead and pass it by reference (you can also find the array psuedo-container in Boost; barring that, consider writing your own. If you take a look at the Boost source code, it's quite simple and straightforward).
Pass a pair of iterators (begin and end) to the function and use them to manipulate the range.
The last option is the most idiomatic C++ approach; it is also the most generic because you can use any type of container, including arrays, standard library containers, or containers that you've written yourself.
Since you are actually trying to use the parameter as an "out" parameter, it's probably better just to return a std::vector<string> or a std::array<string, 100> containing the results; this is much cleaner.
this line is not doing what you are expecting:
initialise_existing_devices(no_of_existing_devices, existing_devices[100])
hint: array index, 100 ...
I would suggest that you use a std::vector<std::string> rather than the array and pass that by reference.
EDIT: okay, given the update:
can you use a struct? If so, you can wrap the array in a struct:
struct string_array
{
string data[100];
};
and then define an instance of this in main, and pass that by reference? I'm sure you can fill in the details.. :)
You should use a std::vector<T> for heap-managed arrays or a boost::/std::array<T, N> for stack-based arrays. These objects will hold their own size.
This is one of those things C++ has in common with C. Arrays are not passed by value. They're demoted to pointers to their first elements. The array syntax in the function parameters is essentially just a comment. You can tell by doing a sizeof(existing_devices) inside your function call. So the answer to your question is that you're already doing it.
You can use templates, like so:
template <size_t size>
initialise_existing_devices(int& no_of_existing_devices, string (&existing_devices)[size])
{
}
or you can do:
typedef string hundred_strings[100];
initialise_existing_devices(int& no_of_existing_devices, hundred_strings &existing_devices)
{
}
For the actual argument, use just the array name, which represents the address of the array:
initialise_existing_devices(no_of_existing_devices, existing_devices);
For the parameter, use this for a constant pointer to the array:
void initialise_existing_devices(int& no_of_existing_devices, string existing_devices[])
That said, using a std::vector as the return type or a reference parameter would avoid the need to guess the number of devices before the call.

how to grow a dynamic array of char pointers (in C++)?

I am trying to work with an array of char pointers.
Let's say I dynamically declare such an array like so:
int numrows=100;
char** array = new char*[numrows];
And then I populate it by using getline to get strings from a file, converting the strings to char arrays, then setting a pointer in my array to point to said char array like so:
string entry;
int i=0;
while (getline(file,entry)){
char* cstring = new char[entry.length()];
array[i]=strncpy(cstring,entry.c_str(),entry.length());
free(cstring);
i++;
}
(this works, but is there a better way to do this?)
The problem is, I don't know how to grow the array once i becomes greater than numrows.
I know how to do this for a single-dimensional array, but the two-dimensionality is throwing me off.
I'm thinking I should be able to grow it the way you would grow a single-dimension array, right?
if (i==numrows){
char** temp = new char*[numrows+numrows];
for (int j=0;j<i;j++){
char* cstring = new char[strlen(array[i])];
temp[i]=strncpy(cstrin,array[i],strlen(array[i]));
free(cstring);
}
delete [] array;
array = temp;
}
So if the current array becomes full, make a second array that is twice the size of the current array and fill it with the contents of the current array. Then delete array and let array point to temp. I'm fine up to making temp the new array. I can get the contents of array into temp, but when I delete array and set array = temp, the contents of array aren't the contents of temp.
So my question is how can/should I be growing this dynamic array of char pointers?
use std::vector - it is your friend
std::vector<std::string> arr;
while(getline(file, entry))
{
arr.push_back(entry);
}
done
sort can be done using vector sort with custom compare
bool less3(const std::string &s1, const std::string &s2)
{
return s1.compare(0, 3, s2, 0, 3) == 0;
}
std::sort(arr.begin(), arr.end(), less3);
I bet that less3 could be made more efficient but readability wins unless you really suffer
edit fixed as per nice comment from gman
Apart from the remarks by Tyler McHenry, and the fact that you should use the STL, the problem is most likely that you are freeing each cstring after having copied it. Perhaps you intended to free the original string instead?
for (int j=0;j<i;j++){
char* cstring = new char[strlen(array[i])];
temp[i]=strncpy(cstring,array[i],strlen(array[i]));
delete[] array[i];
}
When you first populate the array, DO NOT call free() on the string. First of all, you should use delete[], but more importantly, you still want to access that string later, right?
now i see you say that this is a class that does allow you to use STL. A class teaching c++ that forbids one of the major language features! - anyway passing along
You do not need to be copying the strings to resize the array , you just need to copy the pointers.
if (i==numrows){
char** temp = new char*[numrows+numrows];
for (int j=0;j<i;j++){
temp[j]=array[j];
}
delete [] array;
array = temp;
}
i am sure there are still out by ones there - left as homework

A generic method to set the length of a dynamic array of arbitrary type in c++

I am doing a project converting some Pascal (Delphi) code to C++ and would like to write a function that is roughly equivalent to the Pascal "SetLength" method. This takes a reference to a dynamic array, as well as a length and allocates the memory and returns the reference.
In C++ I was thinking of something along the lines of
void* setlength(void* pp, int array_size, int pointer_size, int target_size, ....) {
void * p;
// Code to allocate memory here via malloc/new
// something like: p = reinterpret_cast<typeid(pp)>(p);
// p=(target_size) malloc(array_size);
return p;
}
My question is this: is there a way to pass the pointer type to a function like this and to successfully allocate the memory (perhaps via a typeid parameter?)? Can I use
<reinterpret_cast>
somehow? The ultimate aim would be something like the following in terms of usage:
float*** p;
p=setlength(100,sizeof(float***),sizeof(float**),.....);
class B;
B** cp;
cp=setlength(100,sizeof(B**),sizeof(B*),.....);
Any help would be most welcome. I am aware my suggested code is all wrong, but wanted to convey the general idea. Thanks.
Use std::vector instead of raw arrays.
Then you can simply call its resize() member method.
And make the function a template to handle arbitrary types:
If you want to use your function, it could look something like this:
template <typename T>
std::vector<T>& setlength(std::vector<T>& v, int new_size) {
v.resize(new_size);
return v;
}
But now it's so simple you might want to eliminate the function entirely and just call resize to begin with.
I'm not entirely sure what you're trying to do with the triple-pointers in your example, but it looks like you don't want to resize though, you want to initialize to a certain size, which can be done with the vector constructor:
std::vector<float>v(100);
If you wanted to do it literally, you would do it like this:
template <typename T>
T* SetLength(T* arr, size_t len) {
return static_cast<T*>(realloc(arr, sizeof(T) * len));
}
Note that the array must have been allocated with malloc or calloc. Also note that this does not actually resize the memory—it deallocates the memory and reallocates memory of the appropriate size. If there were any other pointers to the array being passed in, they will be invalid afterwards.
You're really better off using a more idiomatic C++ solution, like std::vector.
For a multidimensional array, probably the best option would be to use boost's multi_array library:
typedef boost::multi_array<float, 3> array_type;
array_type p(boost::extents[100][100][100]); // make an 100x100x100 array of floats
p[1][2][3] = 4.2;
This lets you completely abstract away the allocation and details of setting up the multidimensional array. Plus, because it uses linear storage, you get the efficiency benefits of linear storage with the ease of access of indirections.
Failing that, you have three other major options.
The most C++-y option without using external libraries would be to use a STL container:
std::vector<float **> p;
p.resize(100);
As with multi_array, p will then automatically be freed when it goes out of scope. You can get the vector bounds with p.size(). However the vector will only handle one dimension for you, so you'll end up doing nested vectors (ick!).
You can also use new directly:
float ***p = new float**[100];
To deallocate:
delete [] p;
This has all the disadvantages of std::vector, plus it won't free it for you, and you can't get the size later.
The above three methods will all throw an exception of type std::bad_alloc if they fail to allocate enough memory.
Finally, for completeness, there's the C route, with calloc():
float ***p = (float ***)calloc(100, sizeof(*p));
To free:
free((void*)p);
This comes from C and is a bit uglier with all the casts. For C++ classes it will not call the constructors for you, either. Also, there's no checking that the sizeof in the argument is consistent with the cast.
If calloc() fails to allocate memory it will return NULL; you'll need to check for this and handle it.
To do this the C++ way:
1) As jalf stated, prefer std::vector if you can
2) Don't do void* p. Prefer instead to make your function a template of type T.
The new operator itself is essentially what you are asking for, with the exception that to appropriately allocate for double/triple pointers you must do something along the following lines:
float** data = new float*[size_of_dimension_1];
for ( size_t i=0 ; i<size_of_dimension_1 ; ++i )
data[i] = new float[size_of_dimension_2];
...
// to delete:
for ( size_t i=0 ; i<size_of_dimension_1 ; ++i )
delete [] data[i];
delete [] data;
Edit: I would suggest using one of the many C++ math/matrix libraries out there. I would suggest uBlas.