Problem
(Apologies if I use the wrong terminology, I am used to Java constructors, and have just recently tried implementing them in C++)
I have a constructor class called FileHandler that will make a new instance of a FileHandler with two vectors inside of it (The constructor has been dulled down, as there is a lot of extraneous code not pertinent to this issue):
class FileHandler {
public:
std::vector<std::string> fullPath, fileNames;
FileHandler() {
//Creates two vectors
fullPath;
fileNames;
}
As far as I am aware, this should create two vectors inside of the instance of FileHandler, which can be manipulated normally. However, from a separate file, I call the .push_back() method (again, dulled down):
// This vector is pre-made and pre-filled before this is called,
// and I have verified it _is_ filled
std::vector<FileHandler> fileHandlers;
FileHandler testInstance = fileHandlers.at(index);
testInstance.fullPath.push_back("a_string_here");
std::cout << testInstance.fullPath.at(0);
And I get the following error (at runtime):
std::out_of_range at memory location 0x00000...
What I've tried so far
I had a suspicion that it might not like trying to push_back from outside of the constructor, so I made a separate function inside of the constructor:
void addFullPath(std::string fullPath) {
this->fullPath.push_back(fullPath);
}
However, passing a string in a similar way as before:
std::vector<FileHandler> fileHandlers;
FileHandler testInstance = fileHandlers.at(index);
testInstance.addFullPath("a_string_here");
std::cout << testInstance.fullPath.at(0);
Still gives me the same out_of_range at memory location error.
This implies (at least to me) that the second line; being the .push_back() method, is not functioning as it should. My main hypothesis at this point is that I am not instantiating the vectors in the constructor in the correct format, or that the vectors cannot be edited, however I am as of yet unsure. Please advise.
After running the following similar dummy code, everything worked normally.
There may be an error elsewhere in the extraneous code you did not show.
#ifndef UNTITLED_MYCLASS_H
#define UNTITLED_MYCLASS_H
#include <string>
#include <vector>
class MyClass {
public:
std::vector<std::string> a,b;
MyClass();
};
#endif //UNTITLED_MYCLASS_H
#include "MyClass.h"
MyClass::MyClass() {} //the vectors are dynamic and don't require initialization here
#include <iostream>
#include "MyClass.h"
int main()
{
// should not be file() which is a function call for the default constructor
MyClass file; //declares default object instance
file.a.push_back("a string");
std::cout << file.a.at(0);
return 0;
}
untitled\cmake-build-debug\untitled.exe
a string
Process finished with exit code 0
Issue solved:
My problem was the following line of code:
FileHandler testInstance = fileHandlers.at(i);
I falsely assumed that the testInstance would inherit all properties of fileHandlers.at(i), making it completely usable, however this was not the case. Replacing:
FileHandler testInstance = fileHandlers.at(index);
testInstance.fullPath.push_back("a_string_here");
std::cout << testInstance.fullPath.at(0);
With:
fileHandlers.at(index).fullPath.push_back("a_string_here");
std::cout << fileHandlers.at(index).fullPath.at(0);
Yields expected results.
Related
I'm receiving the message "Use of deleted function" when I combine the use of an ofstream (which I later want to use to record information) and the placement of one class inside another. Here is my minimal example:
#include <iostream>
#include <unistd.h>
#include <fstream>
class Tracker {
private:
std::ofstream tracker_file;
public:
Tracker(const std::string filename) {
tracker_file.open("tracker_file.csv", std::ios_base::app);
}
};
class Penguin {
private:
Tracker p_tracker;
public:
Penguin(
Tracker p_tracker
) : p_tracker(p_tracker) {}
};
int main()
{
Tracker penguin_tracker = Tracker("output");
Penguin gentoo(penguin_tracker);
return 1;
}
I don't understand how these are related, but if I remove the intermediate class then it works, and if I remove the ofstream it works.
In this line in the ctor of Penguin:
) : p_tracker(p_tracker) {}
You attempt to initalize the Tracker p_tracker data member.
Since you pass it an existing Tracker instance, it attempts to use the copy constuctor.
But class Tracker does not have a copy constructor. This is the "deleted function" mentioned in the error you got.
As #NathanPierson wrote in the comment below, this is because of the deleted copy constructor of the std::ofstream member variable tracker_file (and not because of the converting constructor you defined, as I originally wrote).
You could have theoretically solved it by adding a copy ctor to Tracker, something like:
Tracker(Tracker const & other)
{
// ...
}
However - as mentioned above class Tracker has a std::ofstream member which is non copyable.
So the question is what did you mean should happen in this case ?
On a side note: using the same name: p_tracker for both the class data member and the parameter passed to the constructor is a bit confusing and not recomended.
UPDATE:
To answer the question of the OP in the comment below:
If class Penguin only needs to keep a refernce to a Tracker instance, you can do the following (added "m_" prefix to members to diffrentiate them from other variables):
#include <iostream>
#include <fstream>
// No change in Tracker:
class Tracker {
private:
std::ofstream m_tracker_file;
public:
Tracker(const std::string filename) {
m_tracker_file.open("tracker_file.csv", std::ios_base::app);
}
};
// Penguin now holds a reference to Tracker:
class Penguin {
private:
Tracker & m_tracker;
public:
Penguin(
Tracker & tracker
) : m_tracker(tracker) {}
};
int main()
{
Tracker penguin_tracker("output");
Penguin gentoo(penguin_tracker);
return 0;
}
However - this solution requires you to ensure the Tracker penguin_tracker is alive as long as Tracker penguin_tracker is alive (otherwise you will have a dangling reference). In your example it is OK, just mentioned in for the general case.
Another side note: main should return 0 if all went well (not 1). See: What should main() return in C and C++?.
I've searched endlessly on SE for a logical explanation for why this is happening. It is probably something very simple that I've overlooked, however I cannot spot it and would really appreciate some assistance with this.
Last week I implemented a class to read the output of a system call from a .ini file and then find and store the required information into custom objects that are then stored in a vector inside a Config class. It is a Singleton config class storing a unique_ptr for each instance of my custom class that is created.
The thing is, when I implemented this last week on my laptop, I had zero issues reading and writing to my member vector and was able to get it working exactly how I needed it. Since pulling to my desktop computer, this vector, and any STL container that I use as a member of my class, throws a segmentation fault when I try to do anything on it, even get it's size.
I've tried to shorten the code below to only include sections that actually use this vector. I have replaced my config with A, and custom class with T, and no matter where I try to use my member container, or any other test STL containers that I add to the class, I get a segfault.
For the record, I am using Qt with C++11.
Update: This example breaks on line 50 of c.cpp when debugging, and anywhere that tries to call the vector.
Debug points to this line in stl_vector.h
// [23.2.4.2] capacity
/** Returns the number of elements in the %vector. */
size_type
size() const _GLIBCXX_NOEXCEPT
/*-> this line */ { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
main.cpp
#include "c.h"
int main(int argc, char *argv[])
{
C *c = C::getInstance();
delete c;
return 0;
}
t.h - Class stores information from file
#include <string>
class T
{
public:
T();
bool Active();
std::string getA();
void setA(std::string);
private:
std::string a;
};
t.cpp
#include "t.h"
T::T()
{
}
bool T::Active()
{
if(a == "")
{
return false;
}
return true;
}
std::string T::getA()
{
return this->a;
}
void T::setA(std::string newa)
{
this->a = newa;
}
c.h - Class stores T objects and parses file for information
#include "t.h"
#include <QDebug>
#include <vector>
#include <algorithm>
#include <iostream>
#include <memory>
#include <sstream>
#include <fstream>
class C
{
public:
static C* getInstance();
private:
C();
static C* instance;
static bool init;
std::vector<std::unique_ptr<T>> t_list;
void readLines(const std::string&);
};
c.cpp
#include "c.h"
bool C::init = false;
C* C::instance = nullptr;
C::C()
{
system("echo this is a test command > a.ini");
instance->readLines("a.ini");
}
C* C::getInstance()
{
if(!init)
{
instance = new C;
init = true;
}
return instance;
}
void C::readLines(const std::string &path)
{
T* new_t;
std::ifstream file(path.c_str());
if(!file.is_open())
{
qDebug() << "Unable to open " << path.c_str();
}
std::ofstream o("test.txt");
std::string line;
while(std::getline(file, line))
{
// Split string before searching
std::stringstream ss(line);
std::string seg;
std::vector<std::string> split;
std::string left, right;
// Search patterns
size_t find_a = line.find("a");
size_t del = line.find(':');
if(find_a != std::string::npos)
{
o << "test_Size: " << t_list.size() << std::endl;
if(new_t->Active())
{
T* temp = new_t;
std::unique_ptr<T> move_t(temp);
t_list.push_back(std::move(move_t));
}
o << "test: " << t_list.size() << std::endl;
std::string n;
// Check if previous ahas any null elements
// Split string to find a
n = line.substr(line.find("a "));
n = n.substr(n.find(" ", +2));
new_t->setA(n);
}
else
{
continue;
}
}
// Add last a
T* t = new_t;
std::unique_ptr<T> move_t(t);
//t_list.push_back(std::move(move_t));
o << "a: " << t_list.back().get()->getA() << std::endl;
o << t_list.size() << std::endl;
o.close();
file.close();
}
UPDATE after code change:
I see two things now: One is that new_t in C::readlines is never initialized, so this could break when new_t->Active() is called a bit later in the function. However, I believe that the main problem you're running into is in C::C(), where it says
instance->readLines("a.ini");
At this point in the execution, C::instance is not yet initialized -- you're only just constructing the object that would later be assigned to it. Because of this, this in the readlines call is invalid, and any attempt to access object members will cause UB. This latter problem can be fixed by just calling
readLines("a.ini");
in which case the currently constructed object (that will later be instance) is used for this. I have no idea what you want to happen for the first, though, so all I can say is: If you want to have a vector<unique_ptr<T>>, you will have to create objects of type T with either new T() or (arguably preferrably) std::make_unique<T>() and put them in there.
I'll also say that this is a rather ugly way to implement a singleton in C++. I mean, singletons are never really pretty, but if you're going to do it in C++, the usual way is something like the accepted answer of C++ Singleton design pattern .
Old answer:
The problem (if it is the only one, which I cannot verify because you didn't provide an MCVE) is in the lines
T move_t = new_T;
std::unique_ptr<Adapter> ptr_t(&move_t); // <-- particularly this one
m_ts.push_back(std::move(ptr_t));
You're passing a pointer to a local object into a std::unique_ptr, but the whole purpose of std::unique_ptr is to handle objects allocated with new to avoid memory leaks. Not only will the pointer you pass into it be invalid once the scope surrounding this declaration is left, even if that weren't the case the unique_ptr would attempt to delete an object that's not on the heap at the end of its lifecycle. Both problems cause undefined behavior.
To me, it looks as though you really want to use a std::vector<T> instead of std::vector<std::unique_ptr<T>>, but that's a design issue you'll have to answer yourself.
Answering my own question here. I am trying to call a member variable from within the constructor of the object that holds it, so the vector I am trying to access is not yet instantiated and doesn't exist in memory. That is what causes the Segmentation fault to occur, I am trying to access memory that is not allocated yet, hence any call acting on any member of my C class was causing this issue.
I fixed this problem by adding a public function to the class that then calls the private readLines() function. I call that public function from the object that will take ownership of it, and since this occurs after it has been instantiated, the memory is accessible and the problem disappears.
I am having a problem with assigning new values to a dynamic int array that is a data member variable of the class IntersectionFlowRate(). I can initialize and print the values of the array inside the constructor. However, when I exit the constructor to the another class and then later call a function within the IntersectionFlowRate() class passing in variables to overwrite the initial values of the data member it will segmentation fault. I have debugged to find that overwriting the array is causing the seg fault. And that even attempting to access the dynamic array within one of its functions will seg fault.
My question is how can I edit the values of a dynamic int array member variable from within one of its functions i.e setArrayElement(int index, int x).
Here is some of my code. Sorry if I am unclear or missing something ridiculous. I have been stuck on this for hours.
#ifndef INTERSECTIONFLOWRATE_H
#define INTERSECTIONFLOWRATE_H
class IntersectionFlowRate
{
public:
IntersectionFlowRate();
~IntersectionFlowRate();
void setFlowCycle(int index, int flow);
private:
int* m_flowRateMotorCycle;
};
#endif
in the .h file ^
#include "IntersectionFlowRate.h"
#include <cstdlib>
#include <iostream>
#include <new>
using namespace std;
IntersectionFlowRate::IntersectionFlowRate()
{
const int SIZE = 4; //Constant for m_flowRates[] size
//DYNAMIC MEMORY DELETE LATER
m_flowRateMotorCycle = new int[SIZE];
for(int i = 0; i < SIZE; i++){
m_flowRateMotorCycle[i] = 0;
cout << m_flowRateMotorCycle[i] << endl;
cout << "WE GOT HERE" << endl;
}
}
void IntersectionFlowRate::setFlowCycle(int index, int flow){
cout << "INDEX: " << index << endl;
cout << "FLOW: " << flow << endl;
m_flowRateMotorCycle[index] = flow; //seg fault is here
}
I have another class that creates a pointer to a IntersectionFlowRate() object and then calls its setFlowCycle function passing in two VALID ints. With the debugging I was able pass 0 and 3 to the function setFlowCycle(0, 3) just fine and output those variables within the function.
#ifndef TRAFFICSIM_H
#define TRAFFICSIM_H
#include "IntersectionFlowRate.h"
using namespace std;
class TrafficSim
{
public:
TrafficSim(); //Default Constructor
TrafficSim(const char* file); //Constructor
~TrafficSim(); //Destructor
private:
IntersectionFlowRate* m_flowRate;
};
#endif
#include "TrafficSim.h"
#include "IntersectionFlowRate.h"
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
TrafficSim::TrafficSim()
{
IntersectionFlowRate* m_flowRate = new IntersectionFlowRate();
m_flowRate->setFlowCycle(0, 3);
}
I replicated the error with this code. If no one else can I am completely unsure of what is possibly wrong anymore.
You are setting a local variable called m_flowRate, not the member variable m_flowRate of your TrafficSim class:
Instead of this:
TrafficSim::TrafficSim()
{
IntersectionFlowRate* m_flowRate = new IntersectionFlowRate();
m_flowRate->setFlowCycle(0, 3);
}
It should be this:
TrafficSim::TrafficSim()
{
m_flowRate = new IntersectionFlowRate();
m_flowRate->setFlowCycle(0, 3);
}
But overall, it not need be a pointer. It could be an object member within your class. That would cut down on the pointer usage a bit:
class TrafficSim
{
public:
TrafficSim(); //Default Constructor
TrafficSim(const char* file); //Constructor
private:
IntersectionFlowRate m_flowRate;
};
Then:
TrafficSim::TrafficSim()
{
m_flowRate.setFlowCycle(0, 3);
}
As to your question as to how to incorporate usage of std::vector in your class, here is a code sample of the IntersectionFlowRate class, rewritten using vector:
Vector sample
Also, another source of problems is that your classes fail to follow the Rule of 3 when you have pointers to dynamically allocated memory in your class.
Using std::vector takes care of this automatically, but if you insist on using pointers, you need to adhere to the directions at the link posted.
Yes, use a std::vector, it is much simpler, and it is a template so it also pretty fast and works any type (best for primitive types or pointers to objects) , and it also has boundary checking and other useful things.
If you need fast array-like access then you could use std::map which associates a key with a value, like so
std::map<UINT, YourClass*> m_mapIDs_to_YourClass;
When you first start using stl containers they might seem a little strange, but after a short while you cannot do without them, luckily they have been part of the C++ standard for some time now.
Boundary check for both these containers can be done by comparing your iterator to mapYourMap.end(), if they are equal you have passed the last element and trying to access data through the iterator will cause an exception.
Example for std::vector (if vecInt is a vector< int >):
vector<int>::iterator it = vecInt.begind();
if (it == vecInt.end()) return; // vector is empty
do { // runs through elememts until out of bound, useful for searching
i++
while (it != vecInt.end());
due project's requirements, by this week I'm shifted from Java to C++. I'm facing a lot of trouble, but maybe the greater is the "pass-by-value" and... obviously pointers :)
Now I have a big doubt regard the destiny of an object instantiated inside an the constructor of another object. Here my simple SSCCE composed by an header and a cpp file:
#pragma once
#include <map>
class MapReferenceHolder
{
std::map<int, char*>* mapPointer;
public:
MapReferenceHolder();
~MapReferenceHolder();
void setMap(std::map<int,char*>* map);
void addSomeElementToMap();
void MapReferenceHolder::printMap();
};
Here the cpp file containing the main:
#include "MapReferenceHolder.h"
#include <iostream>
using namespace std;
std::map<int, char*>mymap;
MapReferenceHolder::MapReferenceHolder()
{
setMap(&mymap);
}
MapReferenceHolder::~MapReferenceHolder()
{
}
void MapReferenceHolder::setMap(std::map<int, char*>* map){
mapPointer = map;
}
void MapReferenceHolder::addSomeElementToMap(){
(*mapPointer)[0] = "stringONe";
(*mapPointer)[1] = "stringTwo";
}
void MapReferenceHolder::printMap(){
std::map<int, char*>::iterator it = mapPointer->begin();
while (it!=mapPointer->end()){
cout << it->first << " -> " << it->second << "\n";
it++;
}
}
int main(){
MapReferenceHolder m;
m.addSomeElementToMap();
m.printMap();
cin.get();
return 0;
}
This simple example run without problem. But if I move the mymap instantiation inside the constructor, i.e.
MapReferenceHolder::MapReferenceHolder()
{
std::map<int, char*>mymap;
setMap(&mymap);
}
I get thw folowing error:
Unhandled exception at 0x00B2BD3B in Project1.exe: 0xC0000005: Access violation reading location 0xCCCCCCD0.
I guess this is due to the fact that an instance of an object live only inside the block in which is defined. But I'm passing the address of object, so it is still alive!?? Or the compiler destroy it in any case? And more important... is it, then, right create a global variable to store an object instance. How I can use correctly the constructor? I know this is a "newbie" question but I'm try to match project's development needs and my spare time to study is really little. Any help will be great appreciated.
Regards,
microvo
The object is destroyed at the end of the constructor. so you have saved a pointer that is no longer valid.
You need to consider ownership in C++ (Java has a cycle detecting garbage collector so gives you a lot of leeway).
If MapReferenceHolder owns the std::map you should make it a value rather than a pointer, you can always use a reference to it if you need a pointer for some reason. Also get rid of your constructor and destructor unless they contain actual code.
Alternatively you could call delete mapPointer in your destructor but that is adding extra code for no benefit in simple cases like this IMO.
If MapReferenceHolder does not own std::map then you need to require the pointer be passed in and somehow track the lifetime of it somewhere outside this class.
The map object no longer exists once it goes out of scope, regardless of any pointers that hold its address - these are no longer valid. I suggest a search for "constructor initializer list" might help you.
I have a class that holds a vector, which also inherits another class:
class txtExt : public extention
{
private:
string openedFile_;
public:
vector<string> txtVector; //the vector i want to call
};
I fill the vector in a method within a class:
class Manager : public extention
{
// there is some other code here that I know does work
// and it calls this function:
void organizeExtention(string filename, string ext)
{
if(ext == "txt")
{
txtExt txtExt;
txtExt.txtVector.pushback(filename);
}
}
}
and this is my main class where i attempt to call the vector:
int main()
{
// some code here that does previous operations like getting the path
// and filling the vector
// I've tried many ways of trying to call the vector
// here is an example of one:
vector<txtExt*> testVector;
for(int i = 0; i < testVector.size(); ++i)
{
cout << testVector[i] << endl;
}
return 0;
}
I have a few questions:
Am I calling the vector wrong?
Is my vector empty?
Do I have to make my vector global, so other classes can see it?
Note: I've been able to print out the vector where I load the vector using a very simple for loop
Well, as has been said you have a few errors in the code posted, and you maybe have some misunderstandings as well. But to answer the question asked, this
testVector[i]->txtVector
is the way to access the txtVector object that is inside each of your txtExt objects.
If that doesn't work for you then it's because one of the other errors/misunderstandings you have in your code.
To summarize:
reread the first chapters of a good C++ book ( The Definitive C++ Book Guide and List ), then try try to fix your program and deal with each error one at the time.
There are several errors in your code.
First of all, there's no operator << for printing entities of the type txtExt*.
Even object of type txtExt is not printable just like that.
In addition, the testVector you made is empty, so no .size() will be zero, and there's going to be no looping.
Are you really sure that you like to inherit both your classes from 'extension' ?
You can't call a vector, you can access it.
Having a data member (like the vector) public is not a good idea.
Calling a variable by the same name as a class is a very bad idea.
I have trouble guessing what your code should do. Here's a simple example of things you need to understand:
#include <iostream>
#include <vector>
#include <string>
class TxtExt
{
public:
std::vector<std::string> txtVector;
};
int main(){
TxtExt oneTxtExt;
oneTxtExt.txtVector.push_back("hello");
oneTxtExt.txtVector.push_back("world");
for( auto &i : oneTxtExt.txtVector ){
std::cout << i <<std::endl;
}
}
The following code is correct, but has absolutely no effect. You could as well just write {}:
{
TxtExt TxtExt;
TxtExt.txtVector.pushback(filename);
}
You here create a new object, push back to it (btw it is called push_back), but then the object is destroyed at the end of the scope. Also, don't name you objects the same as the class, it becomes really confusing.