Commit c713b44d92e4ea2569101fa6bdf60afa311b29a3

Authored by Jarryd Beck
1 parent b5283241

Use a shared pointer for the options map

Fixes #132. Since the map of options is shared between Options and
ParseResult, they should use a shared pointer instead of a reference so
that ParseResult can be returned without referencing destroyed memory.
include/cxxopts.hpp
@@ -1110,7 +1110,9 @@ namespace cxxopts @@ -1110,7 +1110,9 @@ namespace cxxopts
1110 public: 1110 public:
1111 1111
1112 ParseResult( 1112 ParseResult(
1113 - const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>&, 1113 + const std::shared_ptr<
  1114 + std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
  1115 + >,
1114 std::vector<std::string>, 1116 std::vector<std::string>,
1115 bool allow_unrecognised, 1117 bool allow_unrecognised,
1116 int&, char**&); 1118 int&, char**&);
@@ -1118,8 +1120,8 @@ namespace cxxopts @@ -1118,8 +1120,8 @@ namespace cxxopts
1118 size_t 1120 size_t
1119 count(const std::string& o) const 1121 count(const std::string& o) const
1120 { 1122 {
1121 - auto iter = m_options.find(o);  
1122 - if (iter == m_options.end()) 1123 + auto iter = m_options->find(o);
  1124 + if (iter == m_options->end())
1123 { 1125 {
1124 return 0; 1126 return 0;
1125 } 1127 }
@@ -1132,9 +1134,9 @@ namespace cxxopts @@ -1132,9 +1134,9 @@ namespace cxxopts
1132 const OptionValue& 1134 const OptionValue&
1133 operator[](const std::string& option) const 1135 operator[](const std::string& option) const
1134 { 1136 {
1135 - auto iter = m_options.find(option); 1137 + auto iter = m_options->find(option);
1136 1138
1137 - if (iter == m_options.end()) 1139 + if (iter == m_options->end())
1138 { 1140 {
1139 throw option_not_present_exception(option); 1141 throw option_not_present_exception(option);
1140 } 1142 }
@@ -1182,8 +1184,9 @@ namespace cxxopts @@ -1182,8 +1184,9 @@ namespace cxxopts
1182 const std::string& name 1184 const std::string& name
1183 ); 1185 );
1184 1186
1185 - const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>  
1186 - &m_options; 1187 + const std::shared_ptr<
  1188 + std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
  1189 + > m_options;
1187 std::vector<std::string> m_positional; 1190 std::vector<std::string> m_positional;
1188 std::vector<std::string>::iterator m_next_positional; 1191 std::vector<std::string>::iterator m_next_positional;
1189 std::unordered_set<std::string> m_positional_set; 1192 std::unordered_set<std::string> m_positional_set;
@@ -1196,6 +1199,8 @@ namespace cxxopts @@ -1196,6 +1199,8 @@ namespace cxxopts
1196 1199
1197 class Options 1200 class Options
1198 { 1201 {
  1202 + typedef std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
  1203 + OptionMap;
1199 public: 1204 public:
1200 1205
1201 Options(std::string program, std::string help_string = "") 1206 Options(std::string program, std::string help_string = "")
@@ -1205,6 +1210,7 @@ namespace cxxopts @@ -1205,6 +1210,7 @@ namespace cxxopts
1205 , m_positional_help("positional parameters") 1210 , m_positional_help("positional parameters")
1206 , m_show_positional(false) 1211 , m_show_positional(false)
1207 , m_allow_unrecognised(false) 1212 , m_allow_unrecognised(false)
  1213 + , m_options(std::make_shared<OptionMap>())
1208 , m_next_positional(m_positional.end()) 1214 , m_next_positional(m_positional.end())
1209 { 1215 {
1210 } 1216 }
@@ -1308,7 +1314,7 @@ namespace cxxopts @@ -1308,7 +1314,7 @@ namespace cxxopts
1308 bool m_show_positional; 1314 bool m_show_positional;
1309 bool m_allow_unrecognised; 1315 bool m_allow_unrecognised;
1310 1316
1311 - std::unordered_map<std::string, std::shared_ptr<OptionDetails>> m_options; 1317 + std::shared_ptr<OptionMap> m_options;
1312 std::vector<std::string> m_positional; 1318 std::vector<std::string> m_positional;
1313 std::vector<std::string>::iterator m_next_positional; 1319 std::vector<std::string>::iterator m_next_positional;
1314 std::unordered_set<std::string> m_positional_set; 1320 std::unordered_set<std::string> m_positional_set;
@@ -1466,7 +1472,9 @@ namespace cxxopts @@ -1466,7 +1472,9 @@ namespace cxxopts
1466 inline 1472 inline
1467 ParseResult::ParseResult 1473 ParseResult::ParseResult
1468 ( 1474 (
1469 - const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>& options, 1475 + const std::shared_ptr<
  1476 + std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
  1477 + > options,
1470 std::vector<std::string> positional, 1478 std::vector<std::string> positional,
1471 bool allow_unrecognised, 1479 bool allow_unrecognised,
1472 int& argc, char**& argv 1480 int& argc, char**& argv
@@ -1606,9 +1614,9 @@ inline @@ -1606,9 +1614,9 @@ inline
1606 void 1614 void
1607 ParseResult::add_to_option(const std::string& option, const std::string& arg) 1615 ParseResult::add_to_option(const std::string& option, const std::string& arg)
1608 { 1616 {
1609 - auto iter = m_options.find(option); 1617 + auto iter = m_options->find(option);
1610 1618
1611 - if (iter == m_options.end()) 1619 + if (iter == m_options->end())
1612 { 1620 {
1613 throw option_not_exists_exception(option); 1621 throw option_not_exists_exception(option);
1614 } 1622 }
@@ -1622,8 +1630,8 @@ ParseResult::consume_positional(std::string a) @@ -1622,8 +1630,8 @@ ParseResult::consume_positional(std::string a)
1622 { 1630 {
1623 while (m_next_positional != m_positional.end()) 1631 while (m_next_positional != m_positional.end())
1624 { 1632 {
1625 - auto iter = m_options.find(*m_next_positional);  
1626 - if (iter != m_options.end()) 1633 + auto iter = m_options->find(*m_next_positional);
  1634 + if (iter != m_options->end())
1627 { 1635 {
1628 auto& result = m_results[iter->second]; 1636 auto& result = m_results[iter->second];
1629 if (!iter->second->value().is_container()) 1637 if (!iter->second->value().is_container())
@@ -1737,9 +1745,9 @@ ParseResult::parse(int&amp; argc, char**&amp; argv) @@ -1737,9 +1745,9 @@ ParseResult::parse(int&amp; argc, char**&amp; argv)
1737 for (std::size_t i = 0; i != s.size(); ++i) 1745 for (std::size_t i = 0; i != s.size(); ++i)
1738 { 1746 {
1739 std::string name(1, s[i]); 1747 std::string name(1, s[i]);
1740 - auto iter = m_options.find(name); 1748 + auto iter = m_options->find(name);
1741 1749
1742 - if (iter == m_options.end()) 1750 + if (iter == m_options->end())
1743 { 1751 {
1744 if (m_allow_unrecognised) 1752 if (m_allow_unrecognised)
1745 { 1753 {
@@ -1774,9 +1782,9 @@ ParseResult::parse(int&amp; argc, char**&amp; argv) @@ -1774,9 +1782,9 @@ ParseResult::parse(int&amp; argc, char**&amp; argv)
1774 { 1782 {
1775 const std::string& name = result[1]; 1783 const std::string& name = result[1];
1776 1784
1777 - auto iter = m_options.find(name); 1785 + auto iter = m_options->find(name);
1778 1786
1779 - if (iter == m_options.end()) 1787 + if (iter == m_options->end())
1780 { 1788 {
1781 if (m_allow_unrecognised) 1789 if (m_allow_unrecognised)
1782 { 1790 {
@@ -1814,7 +1822,7 @@ ParseResult::parse(int&amp; argc, char**&amp; argv) @@ -1814,7 +1822,7 @@ ParseResult::parse(int&amp; argc, char**&amp; argv)
1814 ++current; 1822 ++current;
1815 } 1823 }
1816 1824
1817 - for (auto& opt : m_options) 1825 + for (auto& opt : *m_options)
1818 { 1826 {
1819 auto& detail = opt.second; 1827 auto& detail = opt.second;
1820 auto& value = detail->value(); 1828 auto& value = detail->value();
@@ -1892,7 +1900,7 @@ Options::add_one_option @@ -1892,7 +1900,7 @@ Options::add_one_option
1892 std::shared_ptr<OptionDetails> details 1900 std::shared_ptr<OptionDetails> details
1893 ) 1901 )
1894 { 1902 {
1895 - auto in = m_options.emplace(option, details); 1903 + auto in = m_options->emplace(option, details);
1896 1904
1897 if (!in.second) 1905 if (!in.second)
1898 { 1906 {
src/example.cpp
@@ -26,7 +26,8 @@ THE SOFTWARE. @@ -26,7 +26,8 @@ THE SOFTWARE.
26 26
27 #include "cxxopts.hpp" 27 #include "cxxopts.hpp"
28 28
29 -int main(int argc, char* argv[]) 29 +cxxopts::ParseResult
  30 +parse(int argc, char* argv[])
30 { 31 {
31 try 32 try
32 { 33 {
@@ -131,11 +132,20 @@ int main(int argc, char* argv[]) @@ -131,11 +132,20 @@ int main(int argc, char* argv[])
131 132
132 std::cout << "Arguments remain = " << argc << std::endl; 133 std::cout << "Arguments remain = " << argc << std::endl;
133 134
  135 + return result;
  136 +
134 } catch (const cxxopts::OptionException& e) 137 } catch (const cxxopts::OptionException& e)
135 { 138 {
136 std::cout << "error parsing options: " << e.what() << std::endl; 139 std::cout << "error parsing options: " << e.what() << std::endl;
137 exit(1); 140 exit(1);
138 } 141 }
  142 +}
  143 +
  144 +int main(int argc, char* argv[])
  145 +{
  146 + auto result = parse(argc, argv);
  147 + auto arguments = result.arguments();
  148 + std::cout << "Saw " << arguments.size() << " arguments" << std::endl;
139 149
140 return 0; 150 return 0;
141 } 151 }