I have a C++ program as given below. I am trying to pass a std::list from one function to another by value. I expect the list to be accessible in the caller function by means of an iterator? I expect that the return will call the copy constructor of std::list and it will be accessible in the caller. Is my assumption wrong ? If not why am I getting a segmentation fault.
#include <list>
#include <map>
#include <string>
#include <set>
#include <iterator>
#include <iostream>
const char *sy_path = "/var/log";
struct Setting
{
typedef std::list<const Setting*> List;
const char* path;
const char* filename;
const char* name;
int def;
int min;
int max;
struct Original
{
const char* filename;
const char* name;
Original(const char* filename_, const char* name_)
:filename(filename_), name(name_)
{
}
}original;
static const List settings();
};
const Setting::List Setting::settings()
{
const Setting c_settings[] =
{ //default min max
{ sy_path, "cs.cfg", "num_a", 1, 1, 29, Original("sys.cfg", "num_a") }
,{ sy_path, "cs.cfg", "num_b", 1, 1, 6, Original("sys.cfg", "num_b") }
,{ sy_path, "cs.cfg", "num_c", 1, 1, 29, Original("sys.cfg", "num_c") }
};
Setting::List lst;
int numelem = sizeof(c_settings) / sizeof(Setting);
for (int i = 0; i < numelem; i++)
{
const Setting & tmpSetting = c_settings[i];
lst.push_back(&tmpSetting);
}
return lst;
}
static int get_settings(void)
{
Setting::List lst;
lst = Setting::settings();
for (Setting::List::const_iterator it = lst.begin() ; it != lst.end(); ++it)
{
const Setting *cs = *it;
std::cout << "path: " <<cs->path << "filename: " <<cs->filename << "name: " << cs->name << std::endl;
}
}
int main()
{
get_settings();
return 0;
}
Yes, return lst; will return a copy of lst. The problem is that you put in lst pointers to data located on the stack (const Setting c_settings[] variable). These pointers become invalid once you return from function, hence the segmentation fault. The solution is to either allocate memory for your settings on heap, or use a std::list<Setting>.
typedef std::list<Setting> List;
lst.push_back(c_settings[i]); // make sure you have the right copy constructor
or
lst.push_back(new Setting(c_settings[i])); // make sure you have the right copy constructor
Also, I would avoid usage of const char * and use std::string instead.
Related
I need to make an array of string where I can store either 3 or 5 words like {"banana, peach, pear"}, or {"orange", "pear", "silantro", "ginger", "mandarine"}.
I'm confused if I should make an array of string pointer(to dynamically allocate the memory depending on the size of the array-3 or 5), or just have an array of string with the statically allocated memory of 5. And how to initialize it/set it to null/use it in the constructors.
I'm not allowed to use vector.
When I declared an array of size 5, the problem started in the default constructor.
I don't know how to set it to null...
// string multiple_fruits[5]
// multiple_fruits[] = { nullptr, };
So I'm using an array of string pointer here, is there a better way?
What am I doing wrong?? HAAAALP
//.h file
class Fruit {
char* single_fruit;
string* multiple_fruits;
int num_Fruits;
};
//.cpp file
Fruit::Fruit() {
single_fruit = nullptr;
multiple_fruits = nullptr;
num_Fruits = 0;
}
Fruit::Fruit(const char* singlefruit, string* multiplefruits, int numFruits) {
single_fruit = new char[strlen(singlefruit) + 1];
strcpy_s(single_fruit, strlen(singlefruit) + 1, singlefruit);
multiple_fruits = new string[numFruits];
for (int i = 0; i < numFruits; i++) {
multiple_fruits[i] = multiplefruits[i];
}
num_fruits = numFruits;
}
int main() {
Fruit A;
A("apple", {"banana", "peach", "pear"}, 3)
Fruit B;
B("lemon", {"orange", "pear", "silantro", "ginger", "mandarine"}, 5);
return 0;
}
My approach is to use std::string and std::initializer_list for this:
#include <string>
#include <initializer_list>
class Fruit {
public:
Fruit(const std::string &singlefruit, const std::initializer_list<std::string> &multiplefruits) : single_fruit{singlefruit}, multiple_fruits{new std::string[multiplefruits.size()]}, num_Fruits{multiplefruits.size()} {
for (std::size_t i = 0; i < num_Fruits; ++i) {
multiple_fruits[i] = *(multiplefruits.begin() + i);
}
}
~Fruit() {
delete[] multiple_fruits;
}
private:
std::string single_fruit;
std::string *multiple_fruits;
std::size_t num_Fruits;
};
int main() {
Fruit A("apple", {"banana", "peach", "pear"});
Fruit B("lemon", {"orange", "pear", "silantro", "ginger", "mandarine"});
}
I allocated memory for the elements and deleted the memory in the destructor.
You can't declare a variable in one line and call the constructor in the next line.
Here's one way using a proper declaration of the array argument to the constructor.
#include <algorithm> // std::copy
#include <iterator> // std::begin, std::end
#include <string>
#include <iostream>
template<size_t N>
class Fruit {
public:
Fruit();
Fruit(const std::string& singlefruit, const std::string (&multiplefruits)[N]);
size_t size() const;
private:
std::string single_fruit;
std::string multiple_fruits[N];
};
template<size_t N>
Fruit<N>::Fruit() {}
template<size_t N>
Fruit<N>::Fruit(const std::string& singlefruit, const std::string (&multiplefruits)[N])
: // colon indicates the start of the member initializer list
single_fruit(singlefruit)
{
std::copy(std::begin(multiplefruits), std::end(multiplefruits), multiple_fruits);
}
template<size_t N>
size_t Fruit<N>::size() const { return N; }
int main() {
Fruit A("apple", {"banana", "peach", "pear"});
std::cout << A.size() << '\n';
Fruit B("lemon", {"orange", "pear", "silantro", "ginger", "mandarine"});
std::cout << B.size() << '\n';
}
Output:
3
5
Struct that has multiple vectors within
struct data {
//char array1[20];
//char array2[20];
//char array3[20];
vector<string> playerID1;
vector<string> playerID2;
vector<string> overall;
}P1;
struct data P(string b) {
int i = 0;
player_attributes *tmp = new player_attributes;
tmp = head;
while (tmp != NULL) {
if (tmp->potential == b)
{
tmp->Id1 = P1.playerID1[i];
tmp->Id2 = P1.playerID2[i];
tmp->overrall_rating = P1.overall[i];
i++;
tmp = tmp->next;
}
return P1;
}
}
I used i++ initially but I kept getting a vector subscript error.
I really don't know how to iterator this to store values and access them later on.
You get error when i reaches end of vector. std::vector< >::operator[] does not do bound checking and does not create new elements. You have to make sure that you stop when end of vector reached.
Also, why struct of vectors? Why not a vector of structs? Organize it in this way:
#include <string>
#include <iostream>
#include <vector>
using std::string;
using std::vector;
struct data {
string playerID1;
string playerID2;
string overall;
data(const string &i1, const string &i2, const string &ov):
playerID1(i1),playerID2(i2),overall(ov) {}
};
vector<data> P1;
// a little demonsration
int main(int argc, const char *argv[])
{
P1.emplace_back("", "","test1");
P1.emplace_back("", "","test2");
for(auto it = P1.begin(); it != P1.end(); it++ )
{
std::cout << it->overall << std::endl;
}
}
I´m quiet new on C++ and currently learning to understand smart pointers.Therefore I`m currently working on a little console-program for inserting,searching and deleting songs ... for learning purposes to get used to the stuff =)
Here is my code:
Song.hpp
#pragma once
#include <vector>
#include <memory>
#include <string>
class Song
{
public:
typedef std::unique_ptr<Song> pSong;
public:
Song();
~Song();
void setTitle(std::string title);
void setArtist(std::string artist);
void checkSong(std::string item, int iterator);
void get();
private:
std::string _title;
std::string _artist;
};
Song.cpp
#include "Song.hpp"
#include <iostream>
Song::Song()
{
}
Song::~Song()
{
}
void Song::setTitle(std::string title)
{
_title = title;
}
void Song::setArtist(std::string artist)
{
_artist = artist;
}
void Song::checkSong(std::string item, int iterator)
{
if (_artist == item || _title == item)
{
std::cout << "Item found on Slot: " << iterator << std::endl;
}
else
{
std::cout << "No item found!" << std::endl;
}
}
void Song::get()
{
std::cout << _artist << " - " << _title << std::endl;
}
Main.cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
#include "Song.hpp"
//prototype
void IntVector();
void SongVector();
Song* setSong(std::string title, std::string artist);
void find(std::string item, std::vector<Song::pSong> v);
std::vector<Song::pSong> SongList;
int main()
{
int k;
SongVector();
std::cin >> k;
return 0;
}
void IntVector()
{
// Create Vector
std::vector<std::unique_ptr<int>> v;
// Create a few unique_ptr<int> instances and fill them with ints
v.push_back(std::unique_ptr<int>(new int(30)));
v.push_back(std::unique_ptr<int>(new int(600)));
v.push_back(std::unique_ptr<int>(new int(200)));
v.push_back(std::unique_ptr<int>(new int(20)));
v.push_back(std::unique_ptr<int>(new int(200)));
v.push_back(std::unique_ptr<int>(new int(160)));
v.push_back(std::unique_ptr<int>(new int(4)));
v.push_back(std::unique_ptr<int>(new int(5)));
v.push_back(std::unique_ptr<int>(new int(315)));
// define vector<int> for storing values of the unique_ptr
std::vector<int> intList;
for (int i = 0; i < v.size(); i++)
{
// get memory-adress of each element
auto result = v[i].get();
// store value of result-pointer in Vector
intList.push_back(*result);
std::cout << *result << std::endl;
}
// Sort int of new Vector
std::sort(intList.begin(), intList.end());
// Loop through intList and cout
for (int i = 0; i < intList.size(); i++)
{
std::cout << intList[i] << std::endl;
}
}
void SongVector()
{
Song* first = setSong("Afroki","Steve Aoki");
Song* secound = setSong("Hype", "Steve Aoki");
Song* third = setSong("Madness", "Steve Aoki");
Song* fourth = setSong("Cake Face", "Steve Aoki");
SongList.push_back(Song::pSong(first));
SongList.push_back(Song::pSong(secound));
SongList.push_back(Song::pSong(third));
SongList.push_back(Song::pSong(fourth));
for (const auto& song : SongList)
{
song->get();
}
find("Madness", SongList);
}
Song* setSong(std::string title, std::string artist)
{
Song* song = nullptr;
song = new Song;
song->setArtist(artist);
song->setTitle(title);
return song;
}
void find(std::string item, std::vector<Song::pSong> v)
{
int i = 0;
for (const auto& song : v)
{
song->checkSong(item,i);
i++;
}
}
I got following error:
std::unique_ptr<Song,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function
1> with
1> [
1> _Ty=Song
1> ]
I found out, that this error only occurs, when calling my find(...)-method, so I´m guessing that somewhere in there is my mistake, but I just cant find out, what Ive done wrong. Would appreciate your help.
std::unique_ptr provide unique ownership (hense the name) which means beside other you cannot copy instance of std::unique_ptr - which would mean shared ownership. When you passing std::vector<std::unique_ptr<whatever>> by value you creating a copy of vector instance, which tries to copy each element. So simplest solution would be to pass std::vector instance by const reference (as you do not have intention to modify vector):
void find( const std::string &item, const std::vector<Song::pSong>& v);
beside fixing your problem passing by (const) reference is more efficient for non trivial objects, so you can also use it for std::string
in your intVector() function:
for (int i = 0; i < v.size(); i++)
{
// get memory-adress of each element
auto result = v[i].get();
// store value of result-pointer in Vector
intList.push_back(*result);
std::cout << *result << std::endl;
}
you do not really need to get raw pointer, just use std::unique_ptr itself:
for (int i = 0; i < v.size(); i++)
{
// get smart pointer for each element
const auto &result = v[i];
// store value of result-pointer in Vector
intList.push_back(*result);
std::cout << *result << std::endl;
}
void find(std::string item, std::vector<Song::pSong> v)
You need to pass vectors by reference. Add &.
void find(std::string item, std::vector<Song::pSong>& v)
Don't forget to also change the prototype of the function.
It seems the attribute test aisbn is successfully storing the data invoking setCode(), setDigit(). But The trouble starts failing while I attempt these values to store into list<test> simul
The list attribute takes the value of digit after setDigit() but the code. How can I put both code and digit into the list attribute? I can't see where the problem is. The code:
#include <iostream>
#include <stdlib.h>
#include <string>
#include <fstream>
#include <list>
using namespace std;
class test
{
private:
string code;
int digit;
public:
//constructor
test(): code(""), digit(0) { }
//copy constructor
test(const test &other):
digit(other.digit)
{
for(unsigned int i=0; i < code.length(); i++)
code[i] = other.code[i];
}
//set up the private values
void setCode(const string &temp, const int num);
void setCode(const string &temp);
void setDigit(const int &num);
//return the value of the pointer character
const string &getCode() const;
const unsigned int getDigit() const;
};
const string& test::getCode() const
{
return code;
}
const unsigned int test::getDigit() const
{
return digit;
}
void test::setCode(const string &temp, const int num)
{
if((int)code.size() <= num)
{
code.resize(num+1);
}
code[num] = temp[num];
}
void test::setCode(const string &temp)
{
code = temp;
}
void test::setDigit(const int &num)
{
digit = num;
}
int main()
{
const string contents = "dfskr-123";
test aisbn;
list<test> simul;
list<test>::iterator testitr;
testitr = simul.begin();
int count = 0;
cout << contents << '\n';
for(int i=0; i < (int)contents.length(); i++)
{
aisbn.setCode(contents);
aisbn.setDigit(count+1);
simul.push_back(aisbn);
count++;
}
cout << contents << '\n';
/*for(; testitr !=simul.end(); simul++)
{
cout << testitr->getCode() << "\n";
}*/
}
It looks like you are having issues with your for loop, you need to modify your for loop like so:
for(testitr = simul.begin(); testitr !=simul.end(); testitr++)
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^
although, push_back does not invalidate iterators for std::list I think it is more readable to set the iterator where you are using it. Based on your response you also need to modify the copy constructor:
test(const test &other): code(other.code), digit(other.digit) {}
^^^^^^^^^^^^^^^^
how about using the vector
std::vector<test> simul;
for(int i=0; i < (int)contents.length(); i++)
{
aisbn.setCode(contents);
aisbn.setDigit(count+1);
simul.push_back(aisbn);
count++;
}
iterators, pointers and references related to the container are invalidated.
Otherwise, only the last iterator is invalidated.
When I try debugging the code, it runs into the debugging error "c++ Expression: string subscript out of range"
Pretty sure the problem was brought while calling setCode().
How do I fix the code inside setCode()?
#include <iostream>
#include <stdlib.h>
#include <string>
#include <fstream>
#include <list>
using namespace std;
class test
{
private:
string code;
int digit;
public:
//constructor
test(): code(""), digit(0) { }
//copy constructor
test(const test &other):
digit(other.digit)
{
for(unsigned int i=0; i < code.length(); i++)
code[digit] = other.code[digit];
}
//set up the private values
void setCode(const string &temp, const int num);
void setDigit(const int &num);
//return the value of the pointer character
const string &getCode() const;
const unsigned int getDigit() const;
};
const string& test::getCode() const
{
return code;
}
const unsigned int test::getDigit() const
{
return digit;
}
void test::setCode(const string &temp, int num)
{
code[num] = temp[num];
}
void test::setDigit(const int &num)
{
digit = num;
}
int main()
{
string contents = "dfskr-123";
test aisbn;
list<test> simul;
list<test>::iterator testitr;
testitr = simul.begin();
int count = 0;
cout << contents << '\n';
aisbn.setCode(contents, count);
aisbn.setDigit(count);
simul.push_back(aisbn);
count++;
/*for(; testitr !=simul.end(); simul++)
{
cout << testitr->getCode() << "\n";
}*/
}
When you create an instance of the test class, the string inside it is empty. This means that whenever you do e.g. code[something] you will be out of range. It doesn't matter what the index is.
You either need to set the string to a certain length from the start, and make sure that the index is within the range. Or to make sure that the index is within range by dynamically extending the string when needed.
You have to make sure that when this statement executes:
code[num] = temp[num];
both code and temp are at least of size num + 1.