Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

C/C++

Straightforward Settings


Defaults

Ok, so what happens when I want a setting, but it's nowhere to be found? Most of the time, you'll be happy with the default constructed value, which is 0, false, or yourclass().

In case you aren't, you can also set defaults in ss::init_settings. You can set a default just like you would a normal setting, or you can do bulk defaults; See Listing Eight.

void ss::init_settings() {
  def_cfg().add_storage("", file_storage("app.ini");
  ...
  
  // set defaults
  setting("user.name") = "John";
  setting("user.passw") = "secret";
  setting("app.retries") = 5;
  // bulk set of defaults (up to 40 arguments)
  bulk_setting(
    "chart.window.width=100",
    "chart.window.height=50",
    "tmp.del_period=20");
}
Listing Eight

Note that some existing APIs allow you to specify an extra argument, which is to be returned in case the setting is not found. In practice, this just doesn't pay off. You'll forget it some times (in case you need to use the same setting in several places), or even worse, use different defaults in different places. Bugs like that come back to haunt you, so I chose to have a single place where you set the defaults.

Enumerations

In case you have a setting that can be an enumeration, you can persist it as an integer. Or, if you want to be more user friendly, you need to define a to/from string conversion and register it—you'll do this in ss::init_settings. Note that this will work only if boost::is_enum works. Otherwise, you can use enum_ function; check out Listing Nine.

typedef enum answer {
  yes, no, maybe
};

void ss::init_settings() {
  def_cfg().add_storage("", file_storage("app.ini");
  ...
  register_enum<answer>()
    (yes,"Yes")(no,"No")(maybe,"Maybe");
}

// Using enums in code
// ... if boost::is_enum works
answer a = setting("user.default_answer");
setting("user.default_answer") = maybe;

// ... if boost::is_enum does not work
answer a = enum_(setting("user.default_answer"));
enum_(setting("user.default_answer") = maybe;
Listing Nine

The Need for ss::init_settings

The initialization of the library, the defaults and the enumerations are all done in ss::init_settings. They could be done somewhere else, like, in main(), or with global variables, etc. The reason I chose to do it here is because you might need to get/set the settings before main() as part of some global variable's initialization routine. As "but you shouldn't do it" as this sounds like, in practice this happens quite a bit: log initialization, MFC initialization, etc.

Arrays and Collections

To persist an array or a collection, you basically need to persist all its elements. For an STL-like non-associative array (std::vector, std::list, etc), simply use the array() function. For an associative array (std::map, etc) use the coll() function. In case you have a fixed C-like array (to which you assign using the a[i]=val; syntax), use the array(), and pass the array's size as the second argument. See Listing Ten.

std::vector<int> a;
std::map<std::string,long> b;
employee c[20];

array(setting("app.widths")) = a;
a = array(setting("app.widths"));

coll(setting("app.corresp")) = b;
b = coll(setting("app.corresp"));

array(setting("app.empls"),20) = c;
c = array(setting("app.empls"),20);
Listing Ten

Note that both the array() and coll() functions are helpers: they simply read or write the array's size, then generate unique names for each element, and read or write them.

Error Handling

Working with settings, you might end up with exceptions. Here are a few:

  • The setting does not exist, and does not have a default
  • The setting cannot be written to the destination storage (for instance, it's a read-only file)
  • The setting is constant, but you tried to write to it

By default, the errors are ignored (in the third case, you'll get a failed assertion). Otherwise, you can set your own error handler (set_error_handler), to which you pass a callback function with two parameters: an error code (integer) and the error string.

Thread Safety

The library is thread safe, by default (using Windows threads). You can override how it deals with thread-safety issues like this:

  • SETTING_THREAD_SAFE_USE_BOOST - use boost threads
  • SETTING_THREAD_SAFE_USE_WIN - use Windows threads
  • SETTING_NOT_THREAD_SAFE - not thread-safe

Unicode Setting Names

By default, the setting names are char-strings. In case you want to override this, just define the SETTING_CHAR macro.

The Code

You can download the code from here or from www.macadamian.ro/drdobbs/. It's tested on VC 7.1 and gcc 4.0.

Acknowledgements

Many thanks to my faithful reviewers: Bartha Bela, Florin Toma, Marius Bucur, Marius Olteanu, Ovi Deac, Ovi Miron, and Ovi Pana.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.