Skip to content

Commit

Permalink
Update value_semantic to return a boost shared pointer instead of a r…
Browse files Browse the repository at this point in the history
…aw pointer

This will return a managed pointer to the user instead of an unmanaged pointer.
This helps static code analyzers from flagged false positive memory leaks
It is becoming harder and harder for projects to use this project because some customers require a static code analyzer. By returning a managed pointer, those projects can continue to use this amazing library.
  • Loading branch information
cfrandsen authored and cfrandsen committed Jul 1, 2021
1 parent 7bcbb4e commit c0c2230
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 91 deletions.
13 changes: 7 additions & 6 deletions include/boost/program_options/detail/value_semantic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// This file defines template functions that are declared in
// ../value_semantic.hpp.

#include <boost/smart_ptr/make_shared.hpp>
#include <boost/throw_exception.hpp>

// forward declaration
Expand Down Expand Up @@ -185,34 +186,34 @@ namespace boost { namespace program_options {
}

template<class T>
typed_value<T>*
shared_ptr<typed_value<T>>
value()
{
// Explicit qualification is vc6 workaround.
return boost::program_options::value<T>(0);
}

template<class T>
typed_value<T>*
shared_ptr<typed_value<T>>
value(T* v)
{
typed_value<T>* r = new typed_value<T>(v);
shared_ptr<typed_value<T>> r = boost::make_shared<typed_value<T>>(v);

return r;
}

template<class T>
typed_value<T, wchar_t>*
shared_ptr<typed_value<T, wchar_t>>
wvalue()
{
return wvalue<T>(0);
}

template<class T>
typed_value<T, wchar_t>*
shared_ptr<typed_value<T, wchar_t>>
wvalue(T* v)
{
typed_value<T, wchar_t>* r = new typed_value<T, wchar_t>(v);
shared_ptr<typed_value<T, wchar_t>> r = boost::make_shared<typed_value<T, wchar_t>>(v);

return r;
}
Expand Down
13 changes: 11 additions & 2 deletions include/boost/program_options/options_description.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ namespace program_options {
after \-- short name.
*/
option_description(const char* name,
const value_semantic* s);
shared_ptr<const value_semantic> s);

/** Initializes the class with the passed data.
*/
option_description(const char* name,
const value_semantic* s,
shared_ptr<const value_semantic> s,
const char* description);

virtual ~option_description();
Expand Down Expand Up @@ -167,6 +167,15 @@ namespace program_options {
operator()(const char* name,
const char* description);

options_description_easy_init&
operator()(const char* name,
shared_ptr<const value_semantic> s);

options_description_easy_init&
operator()(const char* name,
shared_ptr<const value_semantic> s,
const char* description);

options_description_easy_init&
operator()(const char* name,
const value_semantic* s);
Expand Down
56 changes: 29 additions & 27 deletions include/boost/program_options/value_semantic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <boost/any.hpp>
#include <boost/function/function1.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/smart_ptr/enable_shared_from_this.hpp>

#include <string>
#include <vector>
Expand Down Expand Up @@ -178,7 +179,8 @@ namespace boost { namespace program_options {

/** Class which handles value of a specific type. */
template<class T, class charT = char>
class typed_value : public value_semantic_codecvt_helper<charT>
class typed_value : public enable_shared_from_this<typed_value<T, charT>>,
public value_semantic_codecvt_helper<charT>
#ifndef BOOST_NO_RTTI
, public typed_value_base
#endif
Expand All @@ -196,11 +198,11 @@ namespace boost { namespace program_options {
if none is explicitly specified. The type 'T' should
provide operator<< for ostream.
*/
typed_value* default_value(const T& v)
shared_ptr<typed_value> default_value(const T& v)
{
m_default_value = boost::any(v);
m_default_value_as_text = boost::lexical_cast<std::string>(v);
return this;
return this->shared_from_this();
}

/** Specifies default value, which will be used
Expand All @@ -209,30 +211,30 @@ namespace boost { namespace program_options {
but textual representation of default value must be provided
by the user.
*/
typed_value* default_value(const T& v, const std::string& textual)
shared_ptr<typed_value> default_value(const T& v, const std::string& textual)
{
m_default_value = boost::any(v);
m_default_value_as_text = textual;
return this;
return this->shared_from_this();
}

/** Specifies an implicit value, which will be used
if the option is given, but without an adjacent value.
Using this implies that an explicit value is optional,
*/
typed_value* implicit_value(const T &v)
shared_ptr<typed_value> implicit_value(const T &v)
{
m_implicit_value = boost::any(v);
m_implicit_value_as_text =
boost::lexical_cast<std::string>(v);
return this;
return this->shared_from_this();
}

/** Specifies the name used to to the value in help message. */
typed_value* value_name(const std::string& name)
shared_ptr<typed_value> value_name(const std::string& name)
{
m_value_name = name;
return this;
return this->shared_from_this();
}

/** Specifies an implicit value, which will be used
Expand All @@ -245,36 +247,36 @@ namespace boost { namespace program_options {
operator<< for ostream, but textual representation of default
value must be provided by the user.
*/
typed_value* implicit_value(const T &v, const std::string& textual)
shared_ptr<typed_value> implicit_value(const T &v, const std::string& textual)
{
m_implicit_value = boost::any(v);
m_implicit_value_as_text = textual;
return this;
return this->shared_from_this();
}

/** Specifies a function to be called when the final value
is determined. */
typed_value* notifier(function1<void, const T&> f)
shared_ptr<typed_value> notifier(function1<void, const T&> f)
{
m_notifier = f;
return this;
return this->shared_from_this();
}

/** Specifies that the value is composing. See the 'is_composing'
method for explanation.
*/
typed_value* composing()
shared_ptr<typed_value> composing()
{
m_composing = true;
return this;
return this->shared_from_this();
}

/** Specifies that the value can span multiple tokens.
*/
typed_value* multitoken()
shared_ptr<typed_value> multitoken()
{
m_multitoken = true;
return this;
return this->shared_from_this();
}

/** Specifies that no tokens may be provided as the value of
Expand All @@ -284,17 +286,17 @@ namespace boost { namespace program_options {
'implicit_value' method should be also used. In most
cases, you can use the 'bool_switch' function instead of
using this method. */
typed_value* zero_tokens()
shared_ptr<typed_value> zero_tokens()
{
m_zero_tokens = true;
return this;
return this->shared_from_this();
}

/** Specifies that the value must occur. */
typed_value* required()
shared_ptr<typed_value> required()
{
m_required = true;
return this;
return this->shared_from_this();
}

public: // value semantic overrides
Expand Down Expand Up @@ -381,39 +383,39 @@ namespace boost { namespace program_options {
value of option into program variable.
*/
template<class T>
typed_value<T>*
shared_ptr<typed_value<T>>
value();

/** @overload
*/
template<class T>
typed_value<T>*
shared_ptr<typed_value<T>>
value(T* v);

/** Creates a typed_value<T> instance. This function is the primary
method to create value_semantic instance for a specific type, which
can later be passed to 'option_description' constructor.
*/
template<class T>
typed_value<T, wchar_t>*
shared_ptr<typed_value<T, wchar_t>>
wvalue();

/** @overload
*/
template<class T>
typed_value<T, wchar_t>*
shared_ptr<typed_value<T, wchar_t>>
wvalue(T* v);

/** Works the same way as the 'value<bool>' function, but the created
value_semantic won't accept any explicit value. So, if the option
is present on the command line, the value will be 'true'.
*/
BOOST_PROGRAM_OPTIONS_DECL typed_value<bool>*
BOOST_PROGRAM_OPTIONS_DECL shared_ptr<typed_value<bool>>
bool_switch();

/** @overload
*/
BOOST_PROGRAM_OPTIONS_DECL typed_value<bool>*
BOOST_PROGRAM_OPTIONS_DECL shared_ptr<typed_value<bool>>
bool_switch(bool* v);

}}
Expand Down
28 changes: 23 additions & 5 deletions src/options_description.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// FIXME: this is only to get multiple_occurrences class
// should move that to a separate headers.
#include <boost/program_options/parsers.hpp>
#include <boost/smart_ptr/make_shared.hpp>


#include <boost/lexical_cast.hpp>
Expand Down Expand Up @@ -50,7 +51,7 @@ namespace boost { namespace program_options {

option_description::
option_description(const char* names,
const value_semantic* s)
shared_ptr<const value_semantic> s)
: m_value_semantic(s)
{
this->set_names(names);
Expand All @@ -59,7 +60,7 @@ namespace boost { namespace program_options {

option_description::
option_description(const char* names,
const value_semantic* s,
shared_ptr<const value_semantic> s,
const char* description)
: m_description(description), m_value_semantic(s)
{
Expand Down Expand Up @@ -266,7 +267,7 @@ namespace boost { namespace program_options {
// no value can be specified on command line.
// FIXME: does not look exception-safe
shared_ptr<option_description> d(
new option_description(name, new untyped_value(true), description));
new option_description(name, boost::make_shared<untyped_value>(true), description));

owner->add(d);
return *this;
Expand All @@ -275,7 +276,7 @@ namespace boost { namespace program_options {
options_description_easy_init&
options_description_easy_init::
operator()(const char* name,
const value_semantic* s)
shared_ptr<const value_semantic> s)
{
shared_ptr<option_description> d(new option_description(name, s));
owner->add(d);
Expand All @@ -285,14 +286,31 @@ namespace boost { namespace program_options {
options_description_easy_init&
options_description_easy_init::
operator()(const char* name,
const value_semantic* s,
shared_ptr<const value_semantic> s,
const char* description)
{
shared_ptr<option_description> d(new option_description(name, s, description));

owner->add(d);
return *this;
}

options_description_easy_init&
options_description_easy_init::
operator()(const char* name,
const value_semantic* s)
{
return (*this)(name, shared_ptr<const value_semantic>(s));
}

options_description_easy_init&
options_description_easy_init::
operator()(const char* name,
const value_semantic* s,
const char* description)
{
return (*this)(name, shared_ptr<const value_semantic>(s), description);
}

const unsigned options_description::m_default_line_length = 80;

Expand Down
7 changes: 4 additions & 3 deletions src/value_semantic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <boost/program_options/value_semantic.hpp>
#include <boost/program_options/detail/convert.hpp>
#include <boost/program_options/detail/cmdline.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <set>

#include <cctype>
Expand Down Expand Up @@ -121,16 +122,16 @@ namespace boost { namespace program_options {
value_store = new_tokens.empty() ? std::string("") : new_tokens.front();
}

BOOST_PROGRAM_OPTIONS_DECL typed_value<bool>*
BOOST_PROGRAM_OPTIONS_DECL shared_ptr<typed_value<bool>>
bool_switch()
{
return bool_switch(0);
}

BOOST_PROGRAM_OPTIONS_DECL typed_value<bool>*
BOOST_PROGRAM_OPTIONS_DECL shared_ptr<typed_value<bool>>
bool_switch(bool* v)
{
typed_value<bool>* r = new typed_value<bool>(v);
shared_ptr<typed_value<bool>> r = boost::make_shared<typed_value<bool>>(v);
r->default_value(0);
r->zero_tokens();

Expand Down
2 changes: 1 addition & 1 deletion test/cmdline_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ void apply_syntax(options_description& desc,
stringstream ss;
ss << syntax;
while(ss >> s) {
value_semantic* v = 0;
boost::shared_ptr<value_semantic> v = 0;

if (*(s.end()-1) == '=') {
v = value<string>();
Expand Down
Loading

0 comments on commit c0c2230

Please sign in to comment.