5

I'm making a simple threaded server application in C++, thing is, I use libconfig++ to parse my configuration files. Well, libconfig doesn't support multithreading, thus I'm using two wrapper classes in order to accomplish "support". Point is, one of them fails:

class app_config {
    friend class app_config_lock;
public:
    app_config(char *file) :
        cfg(new libconfig::Config()),
        mutex(new boost::mutex())
    {
        cfg->readFile(file);
    }

private:
    boost::shared_ptr<libconfig::Config> cfg;
    boost::shared_ptr<boost::mutex> mutex;
};

Fails horribly when called from my main.cpp file:

app_main::app_main(int c, char **v) : argc(c), argv(v) {
    // here need code to parse arguments and pass configuration file!.
    try {
        config = app_config("mscs.cfg");
    } catch (libconfig::ParseException &e) {
        cout << "Parse error at line " << e.getLine() << ": " << e.getError() << endl;
        throw;
    } catch (libconfig::FileIOException &e) {
        cout << "Configuration file not found." << endl;
        throw;
    }
}

And it says:

main.cpp: In constructor ‘app_main::app_main(int, char**)’:
main.cpp:38:54: error: no matching function for call to ‘app_config::app_config()’
main.cpp:38:54: note: candidates are:
../include/app_config.h:15:5: note: app_config::app_config(char*)
../include/app_config.h:15:5: note:   candidate expects 1 argument, 0 provided
../include/app_config.h:12:7: note: app_config::app_config(const app_config&)
../include/app_config.h:12:7: note:   candidate expects 1 argument, 0 provided
main.cpp:41:39: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings] (THIS CAN BE IGNORED, I WAS USING STD::STRING, YET CHANGED IT FOR TESTING PURPOSES)

Which is weird because I'm clearly passing an argument, and moreover its a char *!.

Well, as always, any help will be appreciated.

Julian.

Niklas
  • 13,005
  • 23
  • 79
  • 119
Misguided
  • 1,302
  • 1
  • 14
  • 22

2 Answers2

10

You're trying to default-construct your config, and then assign to it later. But you don't have a default constructor.

The correct way to pass an argument to the constructor of a member variable is:

app_main::app_main(int c, char **v) : argc(c), argv(v), config("mscs.cfg")

You can still trap the exception, by using what's known as a function try-block. See http://www.gotw.ca/gotw/066.htm

Final code:

app_main::app_main(int c, char **v)
try : argc(c), argv(v), config("mscs.cfg")
{
    // more constructor logic here
} catch (libconfig::ParseException &e) {
    cout << "Parse error at line " << e.getLine() << ": " << e.getError() << endl;
    throw;
} catch (libconfig::FileIOException &e) {
    cout << "Configuration file not found." << endl;
    throw;
}
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • This solved the problem. However, I plan on passing a variable string, rather than a static string, is there any way I can actually process my argc and argv variables within my app_main member and initialize config after that, rather than in the initialize list? – Misguided Jan 16 '12 at 06:05
  • 1
    @JulianBayardoSpadafora: No. You can pass the arguments of the constructor to member constructors, not just compile-time constants. And you can call static member functions inside the *ctor-initializer-list* as well. Finally, you have control over the order in which members are constructed. But you'll probably need to do argument processing prior to this, and pass in some sort of option bundle object with a `getConfigFilename()` or such member function. Or simply give `app_config` a function to read the file instead of doing it from the constructor. – Ben Voigt Jan 16 '12 at 06:14
4

First of all, don't allocate mutexes dynamically, it serves no purpose. Second of all, it's because you have a data member that cannot be default-constructed, and you didn't initialise it in the ctor init list. Plus, never assign string literals to char* variables (it should be app_config(const char*) if you really want to dabble with char pointers).

Your app_main::app_main should look like this instead:

app_main::app_main(int c, char **v) try
    : argc(c), argv(v), config("mscs.cfg") {
} catch (libconfig::ParseException &e) {
    cout << "Parse error at line " << e.getLine() << ": " << e.getError() << endl;
    throw;
} catch (libconfig::FileIOException &e) {
    cout << "Configuration file not found." << endl;
    throw;
}
Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224