Skip to content

Commit bb1d6df

Browse files
committed
Make Node move constructor and assignment operator noexcept (#809)
Move constructor: * m_isValid (bool) exchange(rhs.m_isValid, true) * m_invalidKey (std::string) std::move() * m_pMemory (shared_memory_holder) std::move() * m_pNode (node*) exchange(rhs.m_pNode, nullptr) This leaves the moved-from Node as if it was just default constructed. Move assignment: A temporary Node is move constructed (using the above) leaving the moved-from Node as if it was just default constructed. *this then copy assigns the temporary, using AssignNode() directly to avoid a second self-assignment check. If an exception is thrown in AssignNode(), m_isValid is set to false. Signed-off-by: Ted Lyngmo <ted@lyncon.se>
1 parent c946011 commit bb1d6df

File tree

2 files changed

+60
-2
lines changed

2 files changed

+60
-2
lines changed

include/yaml-cpp/node/impl.h

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,33 @@
1414
#include "yaml-cpp/node/node.h"
1515
#include <sstream>
1616
#include <string>
17+
#include <utility>
18+
19+
// This is here for compatibility with older versions of Visual Studio
20+
// which don't support noexcept
21+
#if defined(_MSC_VER) && _MSC_VER < 1900
22+
#define YAML_CPP_NOEXCEPT _NOEXCEPT
23+
#else
24+
#define YAML_CPP_NOEXCEPT noexcept
25+
#endif
1726

1827
namespace YAML {
19-
inline Node::Node()
28+
namespace detail {
29+
#if __cplusplus >= 201402L
30+
using ::std::exchange;
31+
#else
32+
template<class T, class U = T>
33+
T exchange(T& obj, U&& new_value) {
34+
T old_value = std::move(obj);
35+
obj = std::forward<U>(new_value);
36+
return old_value;
37+
}
38+
#endif
39+
} // namespace detail
40+
} // namespace YAML
41+
42+
namespace YAML {
43+
inline Node::Node() YAML_CPP_NOEXCEPT
2044
: m_isValid(true), m_invalidKey{}, m_pMemory(nullptr), m_pNode(nullptr) {}
2145

2246
inline Node::Node(NodeType::value type)
@@ -44,6 +68,13 @@ inline Node::Node(const detail::iterator_value& rhs)
4468

4569
inline Node::Node(const Node& rhs) = default;
4670

71+
inline Node::Node(Node&& rhs) YAML_CPP_NOEXCEPT
72+
: m_isValid(detail::exchange(rhs.m_isValid, true)),
73+
m_invalidKey(std::move(rhs.m_invalidKey)),
74+
m_pMemory(std::move(rhs.m_pMemory)),
75+
m_pNode(detail::exchange(rhs.m_pNode, nullptr)) {
76+
}
77+
4778
inline Node::Node(Zombie)
4879
: m_isValid(false), m_invalidKey{}, m_pMemory{}, m_pNode(nullptr) {}
4980

@@ -209,6 +240,19 @@ inline Node& Node::operator=(const Node& rhs) {
209240
return *this;
210241
}
211242

243+
inline Node& Node::operator=(Node&& rhs) YAML_CPP_NOEXCEPT {
244+
if (is(rhs))
245+
return *this;
246+
Node tmp(std::move(rhs));
247+
try {
248+
AssignNode(tmp);
249+
}
250+
catch(...) {
251+
m_isValid = false;
252+
}
253+
return *this;
254+
}
255+
212256
inline void Node::reset(const YAML::Node& rhs) {
213257
if (!m_isValid || !rhs.m_isValid)
214258
throw InvalidNode(m_invalidKey);
@@ -424,4 +468,6 @@ inline void Node::force_insert(const Key& key, const Value& value) {
424468
inline bool operator==(const Node& lhs, const Node& rhs) { return lhs.is(rhs); }
425469
} // namespace YAML
426470

471+
#undef YAML_CPP_NOEXCEPT
472+
427473
#endif // NODE_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66

include/yaml-cpp/node/node.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@
1717
#include "yaml-cpp/node/ptr.h"
1818
#include "yaml-cpp/node/type.h"
1919

20+
// This is here for compatibility with older versions of Visual Studio
21+
// which don't support noexcept
22+
#if defined(_MSC_VER) && _MSC_VER < 1900
23+
#define YAML_CPP_NOEXCEPT _NOEXCEPT
24+
#else
25+
#define YAML_CPP_NOEXCEPT noexcept
26+
#endif
27+
2028
namespace YAML {
2129
namespace detail {
2230
class node;
@@ -41,12 +49,13 @@ class YAML_CPP_API Node {
4149
using iterator = YAML::iterator;
4250
using const_iterator = YAML::const_iterator;
4351

44-
Node();
52+
Node() YAML_CPP_NOEXCEPT;
4553
explicit Node(NodeType::value type);
4654
template <typename T>
4755
explicit Node(const T& rhs);
4856
explicit Node(const detail::iterator_value& rhs);
4957
Node(const Node& rhs);
58+
Node(Node&& rhs) YAML_CPP_NOEXCEPT;
5059
~Node();
5160

5261
YAML::Mark Mark() const;
@@ -81,6 +90,7 @@ class YAML_CPP_API Node {
8190
template <typename T>
8291
Node& operator=(const T& rhs);
8392
Node& operator=(const Node& rhs);
93+
Node& operator=(Node&& rhs) YAML_CPP_NOEXCEPT;
8494
void reset(const Node& rhs = Node());
8595

8696
// size/iterator
@@ -145,4 +155,6 @@ template <typename T>
145155
struct convert;
146156
}
147157

158+
#undef YAML_CPP_NOEXCEPT
159+
148160
#endif // NODE_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66

0 commit comments

Comments
 (0)