i have trouble assigning a vector to another vector. The program crashes - c++

This is a shortened version of my actual code. This doesn't run too.
The line
tempPurchaseAndID[0] = tempPurchase;
causes the crash.
#include<vector>
#include<iostream>
using namespace std;
int main()
{
string* strTempPurchase = new string("", "");
string* tempOneID = new string("", "");
vector<string> temp;//if category name exists in his purchase
vector<string*/*size of two*/> tempPurchase;
vector<string*/*size of two*/> oneID;// vector for one id
vector<string*>* tempPurchaseAndID{};
tempOneID[0] = "2222";
oneID.push_back(tempOneID);
strTempPurchase[0] ="milk";
strTempPurchase[1] = "3";
tempPurchase.push_back(strTempPurchase);
tempPurchaseAndID[0] = tempPurchase;
tempPurchaseAndID[1] = oneID;
std::cin.get();
return 0;
}
Can someone see the problem and suggest a solution?
Thanks in advance.
P.S. I need the pointers for other things so i can't delete the pointers

As already pointed out, your problems start with pointers.
Firstly vector<string*>* tempPurchaseAndID{}; is not a vector but a null-pointer. Deferencing the null-pointer with tempPurchaseAndID[0] leads to a segfault.
It would be better to use just a vector, not a pointer to a vector:
vector<vector<string*> > tempPurchaseAndID;
But even now, your program would still crash in the same line but this time because of another reason: tempPurchaseAndID would have 0-length and there is no element with index 0 in it! So it is better to use push_back, adding elements to the vector at the end:
tempPurchaseAndID.push_back(tempPurchase);
tempPurchaseAndID.push_back(oneID);
Try to reduce the usage of the pointers - they are a source for a lot of errors and bugs.

std::vector supports the assignment operator already, same for std::string.
I don't see any reason why you are messing with pointers here. Copying pointers won't give you what you probably want to achieve.

You're moving passed the first string and attempting to write to a string that just isn't there here:
strTempPurchase[0] ="milk";
strTempPurchase[1] = "3";
Then you do something similar here, with the added problem that you never actually create an instance of strTempPurchase:
tempPurchaseAndID[0] = tempPurchase;
tempPurchaseAndID[1] = oneID;
Also note that handling vectors through pointers is not ideal. If you resize the vector (using push_back, for example) the vector can move its data to another location, thus invalidating your pointers.

Related

Can't make arrays with unspecified length

Basically I am trying to make an array which will get larger every time the user enters a value. Which means I never know how long the array will be. I don't know if this is something to do with my class or anything.
#pragma once
#include <iostream>
#include <string>
#define dexport __declspec(dllexport)
//Im making an DLL
using namespace std;
class dexport API {
private:
string users[] = {"CatMan","ManCat"}; //Line With Error Incomplete Type Is Not Allowed
public:
string getAllUsers(string list[]) {
for (unsigned int a = 0; a < sizeof(list) / sizeof(list[0]); a = a + 1) {
return list[a];
}
}
};
It gives me an error Incomplete type is not allowed. I really have no idea what to do.
Compiler Error
There are a few things wrong with your code. For starters, an array has a fixed size, so, even if your code did compile, it wouldn't work. Normally, the compiler would infer the size of your array from the length of the initializer; but you are creating a class, and it needs to know it, hence the error.
This will solve your compilation problem:
string users[2] = {"CatMan","ManCat"};
But then your array has a fixed size, and that is not what you want, so you need an std::vector:
#include <vector>
[...]
vector<string>users = {"CatMan","ManCat"};
Now you can use the '[]' operator to access the strings, and users.push_back to add new users.
The next problem you need to solve is the way you are trying to return your value: you shouldn't use an argument as an out value (although you can, with either a reference or a pointer). You should decide whether you want to return a reference to your vector, a copy of your vector, or a const reference, for example:
// Returning a copy
vector<string> getAllUsers() {
return users;
}
// Returning a reference
vector<string>& getAllUsers() {
return users;
}
Finally, you are creating a library: you should know that if you want to share memory between different processes, you need to use some kind of shared memory. Currently, every program will keep its own copy of the API.
What you are looking for is an std::vector.
You can find more info here.
It's somewhat similar to an array, except that it allows variable length.
You can use std::vector. It allocate and copy elements to new place if it got out space.
If you wanna make the class yourself for educational reason here is what you should try as a basic solution:
You allocate some memory up front and store its length as capacity. You need a variable(size) to store the number of elements already entered to the class e.g. via a push_back function. Once the size reached capacity, you need to reallocate memory copy over all the elements and then delete the old memory.

Delete a pointer as first key of std::map

I was wondering how to properly delete a pointer which is the first key of a std::map. I can only figure this out for the second key. The first key is only readable.
Example:
std::map<char*,foo> myMap;
char* str = new char[3];
foo bar;
str[0]='h';
str[1]='i';
str[2]='\0';
myMap[str] = bar
/* some code */
for(auto element: myMap)
{
delete [] element.first;
}
This doesn't seem to free the pointer. Did std::map lose the pointer somewhere?
I am working on big data, so I need string structures as light as possible. That's why I worked with char* and not std::string (with a comparator functor given to the map).
EDIT
For more precisions:
I am reading ADN sequences. For each pattern I am reading, i put its position in the map.(std::map>)
I am using char* because std::string allocate more than required number of char
My priority is not time of computing but space in memory.
I hope this help you to understand my question.
Your code already works (but isn't exception safe - a smart pointer would be). Note that when memory is deleted, the program doesn't normally waste time changing it, it just changes some free/in-use records so a future allocation can consider that memory for reuse, so if you try to dereference the deleted pointers you have undefined behaviour but it might seem to still have the old contents - at least for a while. I assume that's why you think the deallocation isn't working....
Your map has two elements and you need to delete the first: it->first is a char* and it->second is a foo. Try the following code:
for(std::map<char*, foo>::iterator it = myMap.begin(); it!=myMap.end(); it++)
{
delete[] it->first;
myMap.erase(it);
}
Hope that helps!
Resolved
Thank you all, loads of your comments help to solve my problem. I succeed in using std::string. I know, i told you that it was too weight. But I found the méthod reserve(size_t n=0) which allow exactly the place we want to. Now, there is no leak anymore.
Thanks again for your answers!
Sources:
http://www.cplusplus.com/reference/string/string/reserve/

c++ vectors and pointers

As i understand if i dont store pointers, everything in c++ gets copied, which can lead to bad performance (ignore the simplicity of my example). So i thought i store my objects as pointers instead of string object inside my vector, thats better for performance right? (assumining i have very long strings and lots of them).
The problem when i try to iterate over my vector of string pointers is i cant extract the actual value from them
string test = "my-name";
vector<string*> names(20);
names.push_back(&test);
vector<string*>::iterator iterator = names.begin();
while (iterator != names.end())
{
std::cout << (*iterator) << ":" << std::endl;
// std::cout << *(*iterator); // fails
iterator++;
}
See the commented line, i have no problem in receiving the string pointer. But when i try to get the string pointers value i get an error (i couldnt find what excatly the error is but the program just fails).
I also tried storing (iterator) in a new string variable and but it didnt help?
You've created the vector and initialized it to contain 20 items. Those items are being default initialized, which in the case of a pointer is a null pointer. The program is having trouble dereferencing those null pointers.
One piece of advice is to not worry about what's most efficient until you have a demonstrated problem. This code would certainly work much better with a vector<string> versus a vector<string*>.
No, no, a thousand times no.
Don't prematurely optimize. If the program is fast, there's no need to worry about performance. In this instance, the pointers clearly reduce performance by consuming memory and time, since each object is only the target of a single pointer!
Not to mention that manual pointer programming tends to introduce errors, especially for novices. Sacrificing correctness and stability for performance is a huge step backwards.
The advantage of C++ is that it simplifies the optimization process by providing encapsulated data structures and algorithms. So when you decide to optimize, you can usually do so by swapping in standard parts.
If you want to learn about optimizing data structures, read up on smart pointers.
This is probably the program you want:
vector<string> names(20, "my-name");
for ( vector<string>::iterator iterator = names.begin();
iterator != names.end();
++ iterator )
{
std::cout << *iterator << '\n';
}
Your code looks like you're storing a pointer to a stack-based variable into a vector. As soon as the function where your string is declared returns, that string becomes garbage and the pointer is invalid. If you're going to store pointers into a vector, you probably need to allocate your strings dynamically (using new).
Have a look at your initialization:
string test = "my-name";
vector<string*> names(20);
names.push_back(&test);
You first create a std::vector with 20 elements.
Then you use push_back to append a 21st element, which points to a valid string. That's fine, but this element is never reached in the loop: the first iteration crashes already since the first 20 pointers stored in the vector don't point to valid strings.
Dereferencing an invalid pointer causes a crash. If you make sure that you have a valid pointers in your vector, **iterator is just fine to access an element.
Try
if (*iterator)
{
std::cout << *(*iterator) << ":" << std::endl;
}
Mark Ransom explains why some of the pointers are now
string test = "my-name";
vector<string*> names(20);
The size of vector is 20, meaning it can hold 20 string pointers.
names.push_back(&test);
With the push_back operation, you are leaving out the first 20 elements and adding a new element to the vector which holds the address of test. First 20 elements of vector are uninitialized and might be pointing to garbage. And the while loop runs till the end of vector whose size is 21 and dereferencing uninitialized pointers is what causing the problem. Since the size of vector can be dynamically increased with a push_back operation, there is no need to explicitly mention the size.
vector<string*> names; // Not explicitly mentioning the size and the rest of
// the program should work as expected.

How to handle passing runtime-sized arrays between classes in C++

Right now I have a simple class that handles the parsing of XML files into ints that are useful to me. Looks something like this:
int* DataParser::getInts(){
*objectNumbers = new int[getSize()];
for (int i=0;i<getSize();i++){
objectNumbers[i]=activeNode->GetNextChild()->GetContent();
}
return objectNumbers;
}
In the main part of the program, I receive this by doing:
int* numbers= data->getInts();
///Do things to numbers[]
delete numbers;
Everything works fine until the delete command, which crashes everything. What is the proper way of doing this?
Part of the problem is that you are not pairing new[] with delete[]. This probably isn't the root of your bug here but you should get in the habbit of doing this.
The bug is almost certainly related to the code that you left commented out. Can you add some more context there so we can see what you're doing with the numbers value?
In general, I find it's much easier to use a vector for this type of problem. It takes the memory management out of the equation and has the added benefit of storing the size with the dynamic memory.
void DataParser::getInts(std::vector<int>& objectNumbers){
for (int i=0;i<getSize();i++){
objectNumbers.push_back(activeNode->GetNextChild()->GetContent());
}
}
...
std::vector<int> numbers;
data.getInts(numbers);
You need to
delete [] numbers;
The rules is whenever you
ptr = new Type[...];
make sure you
delete [] ptr;
instead of the regular
delete ptr;
which will result in undefined behavior (thanks Neil Butterworth) and is intended for deletion of a single instance where ptr points, not an array.
The following line:
*objectNumbers = new int[getSize()];
What does it do? If you are returning objectNumbers, this is a pointer to int, and you should really be doing:
objectNumbers = new int[getSize()];
Anyway, C++ gives you collections (vector, list etc) -- I'd have used one of those instead of a plain array. As noted elsewhere it is important to match your new with a delete and a new [] with a delete [].
Passing arrays around isn't good design -- you are making the implementation public. Try to pass iterators to the begining and end of the array/collection/sequence of ints instead following the STL design.
simply use a std::vector instead;
std::vector<int> DataParser::getInts(){
std::vector<int> objectNumbers(getSize());
for (int i=0;i<getSize();i++){
objectNumbers[i]=activeNode->GetNextChild()->GetContent();
}
return objectNumbers;
}
You will quickly run into trouble and maintenance issues. Consider using std::vector, this is the proper way to do it.

C++ How can I iterate till the end of a dynamic array?

suppose I declare a dynamic array like
int *dynArray = new int [1];
which is initialized with an unknown amount of int values at some point.
How would I iterate till the end of my array of unknown size?
Also, if it read a blank space would its corresponding position in the array end up junked?
Copying Input From users post below:
Thing is:
a) I'm not allowed to use STL (means: no )
b) I want to decompose a string into its characters and store them. So far I wanted to use a function like this:
string breakLine (string line){
int lineSize = line.size();
const char *aux;
aux=line.data();
int index=0;
while (index<=lineSize){
mySynonyms[index]=aux[index];
index++;
}
I thought that the array aux would end up junked if there was a large blank space between the two numbers to be stored (apparently not). And I was wondering if there was a way to iterate till an undefined end in this type of array. Thanks for you answers.
You don't: wrap the array into a structure that remembers its length: std::vector.
std::vector v(1);
std::for_each( v.begin(), v.end(), ... );
No portable way of doing this. Either pass the size together with the array, or, better, use a standard container such as std::vector
Short answer is that you can't. If you have a pointer to the first element of an array, you can't know what the size of the array is. Why do you want to use a array in the first place. You would be much better off using a std::vector if your array can change size dynamically, or a boost::Array if it will be a fixed size.
I don't understand your second question.
Your code needs to keep to track of the array, so the size would never be unknown. (Or you would have to use some library with code that does this.)
I don't understand the last part of your quesiton. Could you elaborate?
You explained in your post below that you want to look at the guts of a std::string.
If you are expecting your stirng to be like a c-string (aka doesn't contain NULLs), then use line.c_str() instead of line.data(). This will guarantee that aux points to a null terminates c-style string.
After that you can iterate until aux[index] == '\0';
Otherwise, you can use line.data() and string.length/size to get it's size like in your example.
However, "decomposing a string into its characters" is pretty pointless, a string is an array of characters. Just make of copy of the string and store that. You are allowed to do:
char ch = line[index];
Better yet, use iterators on the original string!
for(std::string::const_iterator it = line.begin(); it != line.end(); ++it) {
const char ch = *it;
// do whatever with ch
}
a) I'm not allowed to use STL (means:
no )
What?? Who's moronic idea was that?
std::vector isn't part of the "STL" (which is a copyrighted product of HP), but is (and has been for nearly a decade) part of the C++ Language Standard.
If you're not allowed to use the STL (for whatever reason), the first thing you want to do is actually to implement your own version of it – at least the parts you need, with the level of customizability you need. For example, it's probably overkill to make your own vector class parametrizable with a custom allocator. But nevertheless do implement your own lightweight vector. Everything else will result in a bad, hardly maintainable solution.
This smells like homework, and the teacher's objective is to give you a feeling of what it takes to implement dynamic arrays. So far you're getting an F.
You need to realize that when you allocate memory like this
int *dynArray = new int [1];
you allocate precisely one integer, not an indefinite number of integers to be expanded by some unidentified magic. Most importantly, you can only say
dynArray[0] = 78;
but you cannot say
dynArray[1] = 8973;
The element at index 1 does not exist, you're stepping into memory that was not reserved for you. This particular violation will result in a crash later on, when you deallocate the array, because the memory where you stored 8973 belongs to the heap management data structures, and you corrupted your heap.
As many other responders mention, you must know how many elements you have in the array at all times. So, you have to do something along the lines of
int arraySize = 1;
int *dynArray = new int [arraySize];
arraySize goes together with the array, and is best combined with dynArray in one C++ object.
Now, before you assign to dynarray[1], you have to re-allocate the array:
if (index > arraySize) {
int newSize = index+1;
int *newArray = new int[newSize]
// don't forget to copy the data from old array to new
memcpy(newarray dynArray, sizeof *newArray * arraySize);
arraySize = newSize;
dynArray = newArray;
}
// now you're ready!
dynArray[index] = value;
Now, if you want to make it a bit more efficient, you allocate more than you need, so you don't have to allocate each time you add an element. I'll leave this as an exercise to the reader.
And after doing all this, you get to submit your homework and you get to appreciate the humble std::vector that does all of this for you, plus a lot more.
Use a vector, which has a vector.size() function that returns an integer and a vector.end() function that returns an iterator.
You could create a simple Vector class that has only the methods you need. I actually had to recreate the Vector class for a class that I took this year, it's not very difficult.
If there's a value that cannot be valid, you can use that as a sentinel, and make sure all of your arrays are terminated with that. Of course, it's error-prone and will cause hard-to-find bugs when you happen to miss doing it once, but that's what we used to do while reading files in FORTRAN (back in the all-caps days, and before END= became standard).
Yes, I'm dating myself.