Skip to content

Commit

Permalink
Merge pull request #304 from p-ranav/bugfix/260_segfault_copy
Browse files Browse the repository at this point in the history
Marked copy and move constructors as deleted
  • Loading branch information
p-ranav authored Nov 6, 2023
2 parents 3596748 + f84fa84 commit 6a5fbf7
Show file tree
Hide file tree
Showing 6 changed files with 22 additions and 203 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
* [Positional Arguments with Compound Toggle Arguments](#positional-arguments-with-compound-toggle-arguments)
* [Restricting the set of values for an argument](#restricting-the-set-of-values-for-an-argument)
* [Using `option=value` syntax](#using-optionvalue-syntax)
* [Developer Notes](#developer-notes)
* [Copying and Moving](#copying-and-moving)
* [CMake Integration](#cmake-integration)
* [Building, Installing, and Testing](#building-installing-and-testing)
* [Supported Toolchains](#supported-toolchains)
Expand Down Expand Up @@ -1198,7 +1200,7 @@ foo@bar:/home/dev/$ ./main 6
Invalid argument "6" - allowed options: {0, 1, 2, 3, 4, 5}
```

## Using `option=value` syntax
### Using `option=value` syntax

```cpp
#include "argparse.hpp"
Expand Down Expand Up @@ -1234,6 +1236,12 @@ foo@bar:/home/dev/$ ./test --bar=BAR --foo
--bar: BAR
```

## Developer Notes

### Copying and Moving

`argparse::ArgumentParser` is intended to be used in a single function - setup everything and parse arguments in one place. Attempting to move or copy invalidates internal references (issue #260). Thus, starting with v3.0, `argparse::ArgumentParser` copy and move constructors are marked as `delete`.

## CMake Integration

Use the latest argparse in your CMake project without copying any content.
Expand Down
65 changes: 13 additions & 52 deletions include/argparse/argparse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1395,53 +1395,18 @@ class ArgumentParser {
}
}

ArgumentParser(ArgumentParser &&) noexcept = default;
ArgumentParser &operator=(ArgumentParser &&) = default;

ArgumentParser(const ArgumentParser &other)
: m_program_name(other.m_program_name), m_version(other.m_version),
m_description(other.m_description), m_epilog(other.m_epilog),
m_prefix_chars(other.m_prefix_chars),
m_assign_chars(other.m_assign_chars), m_is_parsed(other.m_is_parsed),
m_positional_arguments(other.m_positional_arguments),
m_optional_arguments(other.m_optional_arguments),
m_parser_path(other.m_parser_path), m_subparsers(other.m_subparsers),
m_suppress(other.m_suppress) {
for (auto it = std::begin(m_positional_arguments);
it != std::end(m_positional_arguments); ++it) {
index_argument(it);
}
for (auto it = std::begin(m_optional_arguments);
it != std::end(m_optional_arguments); ++it) {
index_argument(it);
}
for (auto it = std::begin(m_subparsers); it != std::end(m_subparsers);
++it) {
m_subparser_map.insert_or_assign(it->get().m_program_name, it);
m_subparser_used.insert_or_assign(it->get().m_program_name, false);
}

for (const auto &g : other.m_mutually_exclusive_groups) {
MutuallyExclusiveGroup group(*this, g.m_required);
for (const auto &arg : g.m_elements) {
// Find argument in argument map and add reference to it
// in new group
// argument_it = other.m_argument_map.find("name")
auto first_name = arg->m_names[0];
auto it = m_argument_map.find(first_name);
group.m_elements.push_back(&(*it->second));
}
m_mutually_exclusive_groups.push_back(std::move(group));
}
}

~ArgumentParser() = default;

ArgumentParser &operator=(const ArgumentParser &other) {
auto tmp = other;
std::swap(*this, tmp);
return *this;
}
// ArgumentParser is meant to be used in a single function.
// Setup everything and parse arguments in one place.
//
// ArgumentParser internally uses std::string_views,
// references, iterators, etc.
// Many of these elements become invalidated after a copy or move.
ArgumentParser(const ArgumentParser &other) = delete;
ArgumentParser &operator=(const ArgumentParser &other) = delete;
ArgumentParser(ArgumentParser &&) noexcept = delete;
ArgumentParser &operator=(ArgumentParser &&) = delete;

explicit operator bool() const {
auto arg_used = std::any_of(m_argument_map.cbegin(), m_argument_map.cend(),
Expand Down Expand Up @@ -1749,10 +1714,8 @@ class ArgumentParser {
}

bool has_visible_subcommands = std::any_of(
parser.m_subparser_map.begin(),
parser.m_subparser_map.end(),
[] (auto &p) { return !p.second->get().m_suppress; }
);
parser.m_subparser_map.begin(), parser.m_subparser_map.end(),
[](auto &p) { return !p.second->get().m_suppress; });

if (has_visible_subcommands) {
stream << (parser.m_positional_arguments.empty()
Expand Down Expand Up @@ -1842,9 +1805,7 @@ class ArgumentParser {
m_subparser_used.insert_or_assign(parser.m_program_name, false);
}

void set_suppress(bool suppress) {
m_suppress = suppress;
}
void set_suppress(bool suppress) { m_suppress = suppress; }

private:
bool is_valid_prefix_char(char c) const {
Expand Down
2 changes: 0 additions & 2 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ file(GLOB ARGPARSE_TEST_SOURCES
test_choices.cpp
test_compound_arguments.cpp
test_container_arguments.cpp
test_const_correct.cpp
test_default_args.cpp
test_default_value.cpp
test_error_reporting.cpp
Expand All @@ -51,7 +50,6 @@ file(GLOB ARGPARSE_TEST_SOURCES
test_required_arguments.cpp
test_scan.cpp
test_stringstream.cpp
test_value_semantics.cpp
test_version.cpp
test_subparsers.cpp
test_parse_known_args.cpp
Expand Down
31 changes: 0 additions & 31 deletions test/test_const_correct.cpp

This file was deleted.

17 changes: 0 additions & 17 deletions test/test_mutually_exclusive_group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,23 +52,6 @@ TEST_CASE(
std::runtime_error);
}

TEST_CASE(
"Create mutually exclusive group with 2 arguments, then copy the parser" *
test_suite("mutex_args")) {
argparse::ArgumentParser program("test");

auto &group = program.add_mutually_exclusive_group();
group.add_argument("--first");
group.add_argument("--second");

auto program_copy(program);

REQUIRE_THROWS_WITH_AS(
program_copy.parse_args({"test", "--first", "1", "--second", "2"}),
"Argument '--second VAR' not allowed with '--first VAR'",
std::runtime_error);
}

TEST_CASE("Create mutually exclusive group with 3 arguments" *
test_suite("mutex_args")) {
argparse::ArgumentParser program("test");
Expand Down
100 changes: 0 additions & 100 deletions test/test_value_semantics.cpp

This file was deleted.

0 comments on commit 6a5fbf7

Please sign in to comment.