diff --git a/src/Val.cc b/src/Val.cc index 0d5f5ef793..403e24f166 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -4238,6 +4238,19 @@ TEST_CASE("assignment") { CHECK(v2->RefCnt() == 3); } +TEST_CASE("move assignment") { + auto t = zeek::id::find_type("conn_id_ctx"); + auto v1 = zeek::make_intrusive(t); + auto v2 = zeek::make_intrusive(t); + + zeek::ZValElement element1 = zeek::ZValElement(v1, t); + CHECK(v1->RefCnt() == 2); // v1 and element1 + element1 = zeek::ZValElement(v2, t); // Should use move assignment. + + CHECK(v1->RefCnt() == 1); // Only v1 holds the ref. + CHECK(v2->RefCnt() == 2); // v1 and element1 adopted ref from temporary. +} + TEST_CASE("copy constructor") { auto t = zeek::id::find_type("conn_id_ctx"); auto v = zeek::make_intrusive(t); diff --git a/src/Val.h b/src/Val.h index 8bbb63af0d..04d196c79f 100644 --- a/src/Val.h +++ b/src/Val.h @@ -1198,6 +1198,30 @@ public: return *this; } + /** + * Move assignment operator. + * + * Adopts the reference if \a o holds a managed ZVal. + */ + ZValElement& operator=(ZValElement&& o) noexcept { + if ( this == &o ) + return *this; + + if ( is_set && is_managed ) + Unref(zval.ManagedVal()); + + is_set = o.is_set; + is_managed = o.is_managed; + tag = o.tag; + zval = o.zval; // Adopts the reference. + + // Keep is_managed and tag members valid. + o.is_set = false; + o.zval = ZVal(); + + return *this; + } + /** * Assign a ZVal to ZValElement. *