Seg fault unique_ptr with factory design attempt - c++

I'm getting a segmentation fault when trying to use a unique_ptr to create instances of derived classes.
Before, I had coded every instantiation of the seven derived classes, one after the other and the code was working properly.
Current code is the following:
typedef std::unique_ptr<Comum> ComumPtr;
ComumPtr createInstance ( string dom, map<string, string> & config, map<string, string> & config_fields )
{
ComumPtr ptr; // initialized to nullptr.
if ( dom == "voice" ) {
ptr.reset ( new Voice (config, config_fields) );
// } else if ( dom == "account" ) { // FOR OTHER DERIVED CLASSES
// ptr.reset ( new Account (config, config_fields) );
}
return ptr;
}
// At main function:
for (vector<string>::const_iterator cit = for_domain.begin(); cit != for_domain.end(); ++cit) {
const char * section (cit->c_str());
string fsn = *cit + "_fields";
const char * fields_section_name (fsn.c_str());
const char * db_section ("Database");
map <string, string> domain_config = cfg.getSectionConfig (config_file.c_str(), section);
map <string, string> domain_config_fields = cfg.getSectionConfig (config_file.c_str(), fields_section_name);
map <string, string> database_config = cfg.getSectionConfig (config_file.c_str(), db_section);
std::unique_ptr<Comum> domain = createInstance(*cit, domain_config, domain_config_fields);
domain->readDatabaseFields (database_config); // <- segmentation fault
Do you see any reason for this to seg fault?

function createInstance has the chance to return nullptr, you need to check the pointer is valid:
if (domain.get())
{
domain->readDatabaseFields (database_config);
}

This line is the error:
ComumPtr ptr; // initialized to nullptr.
While I understand that nullity is so easy, it's also the best way to shoot yourself in the foot (whether in C++ or Java), because now any single use of the result of this function need be checked.
Instead, you could:
use a Null object: the method readDatabaseFields will just do nothing
choose to throw an exception rather than returning a null pointer
None of the above alternative is inherently better than the other, it very much depends on the situation; however both are better than returning a null unique_ptr.
Supposing you'd elect the exception method:
ComumPtr createInstance ( string dom, map<string, string> & config, map<string, string> & config_fields )
{
if ( dom == "voice" ) {
return ComumPtr ( new Voice (config, config_fields) );
}
if ( dom == "account" ) {
return ComumPtr ( new Account (config, config_fields) );
}
throw std::runtime_error("Unknown config field");
}

Related

Iterate through a vector of objects and find a variable that matches one pulled from a text file

So I have a vector of objects
vector<Module*> moduleVector;
and I need to iterate through it and compare an attribute from the object to another attribute I'm pulling from a text file
I'm using an ifstream and getLine() to store the element that needs to be compared to the object's attribute (fileD is the opened file, markModId is the string variable)
getline(fileD, markModId, ' ');
But I am unsure of how I can refer to the object's attributes in an iterator. So my question is,
how do I compare the attribute from the file to the object using an iterator?
For reference here is my object constructor (id is the attribute I want to compare)
Module::Module(string id, string title, string lecturer, int
courseworkWeight)
{
code = id;
name = title;
lect = lecturer;
cwWeight = courseworkWeight;
exMark = 0; //ex mark initialised as 0
/*
Map to store coursework marks
*/
map<string, float> CWmarks;
//cwMarks.clear(); //cw marks map cleared
//create a map that stores
}
And exMark is the attribute that needs to be added to the object. All attributes in the Module constructor are private.
How do I compare the attribute from the file to the object using an
iterator?
Short answer: Suppose you have an iterator std::vector<Module*>::iterator iter you can access the public members of Module class like:
(*iter)->/*public member*/;
Long answer: First of all, you need a getter for private member id and one setter for exMark, by which you can get the id of each Module and compare to the id from the file and then set its exMark to some value.
std::string getId()const { return code; }
void setExMark(const double newMark) { exMark = newMark; }
If you want to change the first true instance of Module, you can use std::find_if for finding the Module:
std::string idFromFile = "two";
auto Condition = [&idFromFile](Module* element){ return element->getId() == idFromFile; };
auto iter = std::find_if(moduleVector.begin(), moduleVector.end(), Condition);
if(iter != moduleVector.end())
(*iter)->setExMark(10.0); // see this
// ^^^^^^^^^
See a sample code here
For multiple instances you can do:
for(auto iter = moduleVector.begin(); iter != moduleVector.end(); ++iter)
if ( (*iter)->getId() == idFromFile)
(*iter)->setExMark(10.0);
Note: In modern C++ you can use smart pointers, instead of raw pointers, which will delete the objects automatically as it goes out of scope.
Simply dereference the iterator to access its Module* pointer, then you can access the object using operator-> however you want, eg:
for (std::vector<Module*>::iterator iter = moduleVector.begin(), end = moduleVector.end(); iter != end; ++iter)
{
Module *m = *iter;
if (m->code == markModId)
m->exMark = ...;
}
Or, if you are using C++11 or later, let the compiler handle the iterator for you:
for (Module *m : moduleVector)
{
if (m->code == markModId)
m->exMark = ...;
}
Or, use a lambda with one of the standard iteration algorithms, eg:
std::for_each(moduleVector.begin(), moduleVector.end(),
[&](Module *m)
{
if (m->code == markModId)
m->exMark = ...;
}
);
If you are only interested in updating 1 Module, then break the loop when the the desired Module is found:
for (std::vector<Module*>::iterator iter = moduleVector.begin(), end = moduleVector.end(); iter != end; ++iter)
{
Module *m = *iter;
if (m->code == markModId)
{
m->exMark = ...;
break; // <-- add this
}
}
for (Module *m : moduleVector)
{
if (m->code == markModId)
{
m->exMark = ...;
break; // <-- add this
}
}
auto iter = std::find_if(moduleVector.begin(), moduleVector.end(),
[&](Module *m) { return (m->code == markModId); });
if (iter != moduleVector.end())
{
Module *m = *iter;
m->exMark = ...;
}

How to create a list inside a map where both contain pointers?

I'm doing a project which requires
class course;
void add_student(map<int, map<int, list<course *> * > *> &DB, int id);
so when I check the course is not presenting, I want to create a list. Here is my code,
if(semesterIt == studentIt->second->end()){
DB[id][semester] = new list<course *>();
}
But when I run it, the compiler give me this error
no viable overloaded '='
No idea how to fix it. :(
DB[id][semester] = new list<course *>();
is syntactically wrong since DB[id] evaluates to a pointer, not an object or a reference.
My suggestion:
auto& mapPtr = DB[id];
if ( mapPtr == nullptr )
{
mapPtr = new map<int, list<course *> * >;
// Not necessary since mapPtr is a reference to the element.
// DB[id] = mapPtr;
}
auto& course_list_ptr = (*mapPtr)[semester];
if ( course_list_ptr == nullptr )
{
course_list_ptr = new list<course*>;
// Again, not necessary.
// (*mapPtr)[semester] = course_list_ptr;
}

How to pass Array of Objects using PHPCPP, loop through each object and return associative array

I have recently started learning PHPCPP - A C++ library for developing PHP extensions and trying to understand:
how to pass an Array of objects from php to C++ through PHPCPP
library as examples give only info about arrays and objects separately,
then how to loop through each object in C++
and how to return an associative array back to PHP
Can someone point me to the right direction?
I have come up with this example however need some help:
class Curve{
public :
double shape;
double peak;
double tpeak;
double start;
double lag;
double index;
};
Php::Value example1(Php::Parameters &params) {
vector<Curve> c = params[0];
//create an associative array and return to php
std::map< std::string, std::map<std::string, std::map<std::string, std::map<std::string, std::double>>> > data;
// loop through array of objects here or do something with an array
...
data[c.shape][c.peak][c.tpeak][c.start] = 1/12 * c.index;
return data;
}
extern "C" {
PHPCPP_EXPORT void *get_module() {
static Php::Extension myExtension("my_extension", "1.0");
myExtension.add<example1>("example1", {
Php::ByVal("curves", "Array", false);
});
eturn myExtension;
}
}
In contrary to your declaration
Php::ByVal("curves", "Array", false);
I am using
Php::ByVal("curves", "Array", true);
I did not test this piece of code, therefore it may be necessary to add some slight corrections :-)
Good luck!
public:
Php::Value GetAssociativeArray( Php::Parameters &params ) {
if ( params.size( ) < 1 ) {
error_function( "need at least 1 parameter" );
}
if ( ! params[ 0 ].isObject( ) ) {
error_function( "needs an object as first parameter" );
}
//
// what you have to do before you can use this example:
// define the data type data_t, which should be stored in php_array_result
// supply the PHP class the objects in php_array_objects belong to - can be coded in PHP or cpp
// supply the PHP class the objects in php_array_result belong to - can be coded in PHP or cpp
//
// the PHP object associated to the current cpp class
Php::Value self( this );
// the objects received
Php::Value php_array_objects = params[ 0 ];
// the PHP array to return
Php::Array php_array_result;
// the c++ - class
Curve * obj_curve;
// a single PHP object from the PHP array we received
Php::Value php_obj_in
// a single object from the PHP array we are delivering
Php::Object php_obj_out;
// the key of the associative PHP Array
std::string array_key;
// the data to collect in the associative PHP array
data_t data;
// some other data
int64_t data_returned;
for ( int i = 0; i < php_array_objects.size( ) ; i++ ) {
// retrieve the next object
php_obj_in = php_array_objects[ i ];
// cast PHP object to c++-class
obj_curve = ( Curve * ) php_obj_in.implementation( );
// do something with obj_curve
data = obj_curve->do_something( );
// calculate the key
key = "key_" + std::to_string( i );
// to create an object pass in the class name ( Curve ) to the constructor with optional constructor parameters (1,2,3)
php_obj_out = Php::Object( "Curve", 1, 2, 3 );
// set a class member named "class_member" of php_obj_out
php_obj_out[ "class_member" ] = data;
// call the method "class_method" of php_obj_out
data_returned = php_obj_out.call( "class_method", "parameter" );
// add the new created object to the PHP array
php_array_result[ key ] = php_obj_out;
}
return php_array_result;
} // GetAssociativeArray( )

Vector with custom objects: crash when I want to use one received with .at method

I have a class named CConfig, I'm creating new object:
std::vector< CConfig > docs;
CConfig newfile( "somefile.xml", "root" );
printf("%s", newfile.GetTagValue( "servername" )); // this works
docs.push_back( newfile );
When I'm getting this object with .at method
CConfig file = docs.at(0);
printf("%s", file.GetTagValue( "servername" )); // this crashes
Where's the problem?
(im sorry if formatting is wrong but currently I don't use javascript because my bandwidth is ended and max speed is 1kb/s so I'll try to fix it later)
CConfig.h:
class CConfig
{
TiXmlDocument m_doc;
TiXmlElement* m_pRoot;
bool m_bIsLoaded;
public:
CConfig ( void ) {};
CConfig ( const char * pszFileName, const char * pszRootName );
~CConfig ( void ) {};
const char* GetTagValue ( const char * pszTagName );
const char* GetTagAttribute ( const char * pszTagName, const char * pszAttributeName );
TiXmlElement* GetRootElement ( void ) { return m_pRoot; };
bool IsAvailable ( void ) { return m_bIsLoaded; };
};
CConfig.cpp
#include "CConfig.h"
CConfig::CConfig( const char * pszFileName, const char * pszRootName )
{
m_bIsLoaded = m_doc.LoadFile( pszFileName );
if( m_bIsLoaded )
m_pRoot = m_doc.FirstChildElement( pszRootName );
}
const char * CConfig::GetTagValue( const char * pszTagName )
{
if( m_bIsLoaded && m_pRoot )
{
TiXmlElement * element = m_pRoot->FirstChildElement( pszTagName );
if( element )
return element->GetText();
}
}
const char * CConfig::GetTagAttribute( const char * pszTagName, const char * pszAttributeName )
{
if( m_bIsLoaded && m_pRoot )
{
TiXmlElement * element = m_pRoot->FirstChildElement( pszTagName );
if( element )
return element->Attribute( pszAttributeName );
}
}
I'm using tinyxml
Your issue is with pointers to old memory. When you add an item to an array, it is copied. Later you leave that scope and the original is destroyed, but ask yourself where the pointer in your copy is pointing? Still to the first (now deleted) object's memory. Uh-oh.
The simplest fix (while avoiding large copy operations) is to make m_doc into a shared pointer (available in the standard in C++11, or via Boost in C++03). That will then handle everything for you rule-of-3 wise. And because the underlying memory won't move, m_pRoot will remain valid until the last copy has been deleted.
If copy-space is not an issue, then fix your Rule of Three violation by properly adding a copy constructor:
CConfig(const CConfig& obj)
: m_doc(obj.m_doc)
, m_bLoaded(obj.m_bLoaded)
, m_pRoot()
{
if (m_bLoaded)
m_pRoot = m_doc.GetRootElement();
}
An assignment operator is also likely in order, but if you don't need it, hide it by declaring it (but not implementing it) as private or use the C++11 delete attribute feature.
Interestingly enough, you don't even need the m_bLoaded member. A non-NULL root pointer can indicate your loaded-state, but that is a separate issue. This at least be enough to get you up and running.

C++ STL Set: Cannot find() last element inserted

I am in the process of writing an application in which I use the Set class in the C++ STL. I've discovered that the call to set->find() always seems to fail when I query for the last element I inserted. However, if I iterate over the set, I am able to see the element I was originally querying for.
To try to get a grasp on what is going wrong, I've created a sample application that exhibits the same behavior that I am seeing. My test code is posted below.
For the actual application itself, I need to store pointers to objects in the set. Is this what is causing the weird behavior. Or is there an operator I need to overload in the class I am storing the pointer of?
Any help would be appreciated.
#include <stdio.h>
#include <set>
using namespace std;
#define MySet set<FileInfo *,bool(*)(const FileInfo *, const FileInfo*)>
class FileInfo
{
public:
FileInfo()
{
m_fileName = 0;
}
FileInfo( const FileInfo & file )
{
setFile( file.getFile() );
}
~FileInfo()
{
if( m_fileName )
{
delete m_fileName;
m_fileName = 0;
}
}
void setFile( const char * file )
{
if( m_fileName )
{
delete m_fileName;
}
m_fileName = new char[ strlen( file ) + 1 ];
strcpy( m_fileName, file );
}
const char * getFile() const
{
return m_fileName;
}
private:
char * m_fileName;
};
bool fileinfo_comparator( const FileInfo * f1, const FileInfo* f2 )
{
if( f1 && ! f2 ) return -1;
if( !f1 && f2 ) return 1;
if( !f1 && !f2 ) return 0;
return strcmp( f1->getFile(), f2->getFile() );
}
void find( MySet *s, FileInfo * value )
{
MySet::iterator iter = s->find( value );
if( iter != s->end() )
{
printf( "Found File[%s] at Item[%p]\n", (*iter)->getFile(), *iter );
}
else
{
printf( "No Item found for File[%s]\n", value->getFile() );
}
}
int main()
{
MySet *theSet = new MySet(fileinfo_comparator);
FileInfo * profile = new FileInfo();
FileInfo * shell = new FileInfo();
FileInfo * mail = new FileInfo();
profile->setFile( "/export/home/lm/profile" );
shell->setFile( "/export/home/lm/shell" );
mail->setFile( "/export/home/lm/mail" );
theSet->insert( profile );
theSet->insert( shell );
theSet->insert( mail );
find( theSet, profile );
FileInfo * newProfile = new FileInfo( *profile );
find( theSet, newProfile );
FileInfo * newMail = new FileInfo( *mail );
find( theSet, newMail );
printf( "\nDisplaying Contents of Set:\n" );
for( MySet::iterator iter = theSet->begin();
iter != theSet->end(); ++iter )
{
printf( "Item [%p] - File [%s]\n", *iter, (*iter)->getFile() );
}
}
The Output I get from this is:
Found File[/export/home/lm/profile] at Item[2d458]
Found File[/export/home/lm/profile] at Item[2d458]
No Item found for File[/export/home/lm/mail]
Displaying Contents of Set:
Item [2d478] - File [/export/home/lm/mail]
Item [2d468] - File [/export/home/lm/shell]
Item [2d458] - File [/export/home/lm/profile]
**Edit
It's kind of sad that I have to add this. But as I mentioned before, this is a sample application that was pulled from different parts of a larger application to exhibit the failure I was receiving.
It is meant as a unit test for calling set::find on a set populated with heap allocated pointers. If you have a problem with all the new()s, I'm open to suggestions on how to magically populate a set with heap allocated pointers without using them. Otherwise commenting on "too many new() calls" will just make you look silly.
Please focus on the actual problem that was occurring (which is now solved). Thanks.
***Edit
Perhaps I should have put these in my original question. But I was hoping there would be more focus on the problem with the find() (or as it turns out fileinfo_comparator function that acts more like strcmp than less), then a code review of a copy-paste PoC unit test.
Here are some points about the code in the full application itself.
FileInfo holds a lot of data along with the filename. It holds SHA1 sums, file size, mod time, system state at last edit, among other things. I have cut out must of it's code for this post. It violates the Rule of 3 in this form (Thanks #Martin York. See comments for wiki link).
The use of char* over std::string was originally chosen because of the use of 3rd_party APIs that accept char*. The app has since evolved from then. Changing this is not an option.
The data inside FileInfo is polled from a named pipe on the system and is stored in a Singleton for access across many threads. (I would have scope issues if I didn't allocate on heap)
I chose to store pointers in the Set because the FileInfo objects are large and constantly being added/removed from the Set. I decided pointers would be better than always copying large structures into the Set.
The if statement in my destructor is needless and a left over artifact from debugging of an issue I was tracking down. It should be pulled out because it is unneeded.
Your comparison function is wrong - it returns bool, not integer as strcmp(3). The return statement should be something like:
return strcmp( f1->getFile(), f2->getFile() ) < 0;
Take a look here.
Also, out of curiosity, why not just use std::set<std::string> instead? STL actually has decent defaults and frees you from a lot of manual memory management.
It looks to me like your FileInfo doesn't work correctly (at least for use in a std::set). To be stored in a std::set, the comparison function should return a bool indicating that the two parameters are in order (true) or out of order (false).
Given what your FileInfo does (badly designed imitation of std::string), you'd probably be better off without it completely. As far as I can see, you can use std::string in its place without any loss of functionality. You're also using a lot of dynamic allocation for no good reason (and leaking a lot of what you allocate).
#include <set>
#include <iostream>
#include <iterator>
#include <string>
int main() {
char *inputs[] = { "/export/home/lm/profile", "/export/home/lm/shell", "/export/home/lm/mail" };
char *outputs[] = {"Found: ", "Could **not** find: "};
std::set<std::string> MySet(inputs, inputs+3);
for (int i=0; i<3; i++)
std::cout
<< outputs[MySet.find(inputs[i]) == MySet.end()]
<< inputs[i] << "\n";
std::copy(MySet.begin(), MySet.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}
Edit: even when (or really, especially when) FileInfo is more complex, it shouldn't attempt to re-implement string functionality on its own. It should still use an std::string for the file name, and implement an operator< that works with that:
class FileInfo {
std::string filename;
public:
// ...
bool operator<(FileInfo const &other) const {
return filename < other.filename;
}
FileInfo(char const *name) : filename(name) {}
};
std::ostream &operator(std::ostream &os, FileInfo const &fi) {
return os << fi.filename;
}
int main() {
// std::set<std::string> MySet(inputs, inputs+3);
std:set<FileInfo> MySet(inputs, inputs+3);
// ...
std::copy(MySet.begin(), MySet.end(),
std::ostream_iterator<FileInfo>(std::cout, "\n"));
}
In your constructor:
FileInfo( const FileInfo & file )
{
setFile( file.getFile() );
}
m_fileName seems to be not initialized.