Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[C++] Support C++ object copies #5988

Merged
merged 1 commit into from
Jan 29, 2022
Merged

[C++] Support C++ object copies #5988

merged 1 commit into from
Jan 29, 2022

Conversation

jfroy
Copy link
Contributor

@jfroy jfroy commented Jun 19, 2020

Augment the C++ generator to emit C++ copy/move constructors and assignment operators. This is enabled by default when the C++ standard is C++11 or later. These additional functions are only emitted for objects that need it.

The copy ctor and assignment operator are declared in the object table type and are defined as inline functions after table declarations.

When copy/move ctors and assignment operators are declared, a user-defined explicitly-defaulted default ctor is also emitted.

--- a/tests/cpp17/generated_cpp17/monster_test_generated.h
+++ b/tests/cpp17/generated_cpp17/monster_test_generated.h
@@ -1012,6 +1012,11 @@ struct MonsterT : public flatbuffers::NativeTable {
   MyGame::Example::AnyAmbiguousAliasesUnion any_ambiguous{};
   std::vector<MyGame::Example::Color> vector_of_enums{};
   MyGame::Example::Race signed_enum = MyGame::Example::Race::None;
+  MonsterT() = default;
+  MonsterT(const MonsterT &o);
+  MonsterT(MonsterT&&) FLATBUFFERS_NOEXCEPT = default;
+  MonsterT &operator=(const MonsterT &o);
+  MonsterT &operator=(MonsterT&&) FLATBUFFERS_NOEXCEPT = default;
 };
 
 /// an example documentation comment: "monster object"
@@ -2285,6 +2290,176 @@ inline flatbuffers::Offset<Referrable> CreateReferrable(flatbuffers::FlatBufferB
       _id);
 }
 
+inline MonsterT::MonsterT(const MonsterT &o)
+      : pos((o.pos) ? new MyGame::Example::Vec3(*o.pos) : nullptr),
+        mana(o.mana),
+        hp(o.hp),
+        name(o.name),
+        color(o.color),
+        test(o.test),
+        enemy((o.enemy) ? new MyGame::Example::MonsterT(*o.enemy) : nullptr),
+        testempty((o.testempty) ? new MyGame::Example::StatT(*o.testempty) : nullptr),
+        testbool(o.testbool),
+        testhashs32_fnv1(o.testhashs32_fnv1),
+        testhashu32_fnv1(o.testhashu32_fnv1),
+        testhashs64_fnv1(o.testhashs64_fnv1),
+        testhashu64_fnv1(o.testhashu64_fnv1),
+        testhashs32_fnv1a(o.testhashs32_fnv1a),
+        testhashu32_fnv1a(o.testhashu32_fnv1a),
+        testhashs64_fnv1a(o.testhashs64_fnv1a),
+        testhashu64_fnv1a(o.testhashu64_fnv1a),
+        testf(o.testf),
+        testf2(o.testf2),
+        testf3(o.testf3),
+        parent_namespace_test((o.parent_namespace_test) ? new MyGame::InParentNamespaceT(*o.parent_namespace_test) : nullptr),
+        single_weak_reference(o.single_weak_reference),
+        co_owning_reference(o.co_owning_reference),
+        non_owning_reference(o.non_owning_reference),
+        any_unique(o.any_unique),
+        any_ambiguous(o.any_ambiguous),
+        signed_enum(o.signed_enum) {
+  inventory.clear();
+  inventory.reserve(o.inventory.size());
+  for (const auto &v : o.inventory) { inventory.emplace_back(v); }
+  test4.clear();
+  test4.reserve(o.test4.size());
+  for (const auto &v : o.test4) { test4.emplace_back(v); }
+  testarrayofstring.clear();
+  testarrayofstring.reserve(o.testarrayofstring.size());
+  for (const auto &v : o.testarrayofstring) { testarrayofstring.emplace_back(v); }
+  testarrayoftables.clear();
+  testarrayoftables.reserve(o.testarrayoftables.size());
+  for (const auto &v : o.testarrayoftables) { testarrayoftables.emplace_back((v) ? new MyGame::Example::MonsterT(*v) : nullptr); }
+  testnestedflatbuffer.clear();
+  testnestedflatbuffer.reserve(o.testnestedflatbuffer.size());
+  for (const auto &v : o.testnestedflatbuffer) { testnestedflatbuffer.emplace_back(v); }
+  testarrayofbools.clear();
+  testarrayofbools.reserve(o.testarrayofbools.size());
+  for (const auto &v : o.testarrayofbools) { testarrayofbools.emplace_back(v); }
+  testarrayofstring2.clear();
+  testarrayofstring2.reserve(o.testarrayofstring2.size());
+  for (const auto &v : o.testarrayofstring2) { testarrayofstring2.emplace_back(v); }
+  testarrayofsortedstruct.clear();
+  testarrayofsortedstruct.reserve(o.testarrayofsortedstruct.size());
+  for (const auto &v : o.testarrayofsortedstruct) { testarrayofsortedstruct.emplace_back(v); }
+  flex.clear();
+  flex.reserve(o.flex.size());
+  for (const auto &v : o.flex) { flex.emplace_back(v); }
+  test5.clear();
+  test5.reserve(o.test5.size());
+  for (const auto &v : o.test5) { test5.emplace_back(v); }
+  vector_of_longs.clear();
+  vector_of_longs.reserve(o.vector_of_longs.size());
+  for (const auto &v : o.vector_of_longs) { vector_of_longs.emplace_back(v); }
+  vector_of_doubles.clear();
+  vector_of_doubles.reserve(o.vector_of_doubles.size());
+  for (const auto &v : o.vector_of_doubles) { vector_of_doubles.emplace_back(v); }
+  vector_of_referrables.clear();
+  vector_of_referrables.reserve(o.vector_of_referrables.size());
+  for (const auto &v : o.vector_of_referrables) { vector_of_referrables.emplace_back((v) ? new MyGame::Example::ReferrableT(*v) : nullptr); }
+  vector_of_weak_references.clear();
+  vector_of_weak_references.reserve(o.vector_of_weak_references.size());
+  for (const auto &v : o.vector_of_weak_references) { vector_of_weak_references.emplace_back(v); }
+  vector_of_strong_referrables.clear();
+  vector_of_strong_referrables.reserve(o.vector_of_strong_referrables.size());
+  for (const auto &v : o.vector_of_strong_referrables) { vector_of_strong_referrables.emplace_back((v) ? new MyGame::Example::ReferrableT(*v) : nullptr); }
+  vector_of_co_owning_references.clear();
+  vector_of_co_owning_references.reserve(o.vector_of_co_owning_references.size());
+  for (const auto &v : o.vector_of_co_owning_references) { vector_of_co_owning_references.emplace_back((v) ? new ReferrableT(*v) : nullptr); }
+  vector_of_non_owning_references.clear();
+  vector_of_non_owning_references.reserve(o.vector_of_non_owning_references.size());
+  for (const auto &v : o.vector_of_non_owning_references) { vector_of_non_owning_references.emplace_back(v); }
+  vector_of_enums.clear();
+  vector_of_enums.reserve(o.vector_of_enums.size());
+  for (const auto &v : o.vector_of_enums) { vector_of_enums.emplace_back(v); }
+}
+
+inline MonsterT &MonsterT::operator=(const MonsterT &o) {
+  pos.reset((o.pos) ? new MyGame::Example::Vec3(*o.pos) : nullptr);
+  mana = o.mana;
+  hp = o.hp;
+  name = o.name;
+  color = o.color;
+  test = o.test;
+  enemy.reset((o.enemy) ? new MyGame::Example::MonsterT(*o.enemy) : nullptr);
+  testempty.reset((o.testempty) ? new MyGame::Example::StatT(*o.testempty) : nullptr);
+  testbool = o.testbool;
+  testhashs32_fnv1 = o.testhashs32_fnv1;
+  testhashu32_fnv1 = o.testhashu32_fnv1;
+  testhashs64_fnv1 = o.testhashs64_fnv1;
+  testhashu64_fnv1 = o.testhashu64_fnv1;
+  testhashs32_fnv1a = o.testhashs32_fnv1a;
+  testhashu32_fnv1a = o.testhashu32_fnv1a;
+  testhashs64_fnv1a = o.testhashs64_fnv1a;
+  testhashu64_fnv1a = o.testhashu64_fnv1a;
+  testf = o.testf;
+  testf2 = o.testf2;
+  testf3 = o.testf3;
+  parent_namespace_test.reset((o.parent_namespace_test) ? new MyGame::InParentNamespaceT(*o.parent_namespace_test) : nullptr);
+  single_weak_reference = o.single_weak_reference;
+  co_owning_reference = o.co_owning_reference;
+  non_owning_reference = o.non_owning_reference;
+  any_unique = o.any_unique;
+  any_ambiguous = o.any_ambiguous;
+  signed_enum = o.signed_enum;
+  inventory.clear();
+  inventory.reserve(o.inventory.size());
+  for (const auto &v : o.inventory) { inventory.emplace_back(v); }
+  test4.clear();
+  test4.reserve(o.test4.size());
+  for (const auto &v : o.test4) { test4.emplace_back(v); }
+  testarrayofstring.clear();
+  testarrayofstring.reserve(o.testarrayofstring.size());
+  for (const auto &v : o.testarrayofstring) { testarrayofstring.emplace_back(v); }
+  testarrayoftables.clear();
+  testarrayoftables.reserve(o.testarrayoftables.size());
+  for (const auto &v : o.testarrayoftables) { testarrayoftables.emplace_back((v) ? new MyGame::Example::MonsterT(*v) : nullptr); }
+  testnestedflatbuffer.clear();
+  testnestedflatbuffer.reserve(o.testnestedflatbuffer.size());
+  for (const auto &v : o.testnestedflatbuffer) { testnestedflatbuffer.emplace_back(v); }
+  testarrayofbools.clear();
+  testarrayofbools.reserve(o.testarrayofbools.size());
+  for (const auto &v : o.testarrayofbools) { testarrayofbools.emplace_back(v); }
+  testarrayofstring2.clear();
+  testarrayofstring2.reserve(o.testarrayofstring2.size());
+  for (const auto &v : o.testarrayofstring2) { testarrayofstring2.emplace_back(v); }
+  testarrayofsortedstruct.clear();
+  testarrayofsortedstruct.reserve(o.testarrayofsortedstruct.size());
+  for (const auto &v : o.testarrayofsortedstruct) { testarrayofsortedstruct.emplace_back(v); }
+  flex.clear();
+  flex.reserve(o.flex.size());
+  for (const auto &v : o.flex) { flex.emplace_back(v); }
+  test5.clear();
+  test5.reserve(o.test5.size());
+  for (const auto &v : o.test5) { test5.emplace_back(v); }
+  vector_of_longs.clear();
+  vector_of_longs.reserve(o.vector_of_longs.size());
+  for (const auto &v : o.vector_of_longs) { vector_of_longs.emplace_back(v); }
+  vector_of_doubles.clear();
+  vector_of_doubles.reserve(o.vector_of_doubles.size());
+  for (const auto &v : o.vector_of_doubles) { vector_of_doubles.emplace_back(v); }
+  vector_of_referrables.clear();
+  vector_of_referrables.reserve(o.vector_of_referrables.size());
+  for (const auto &v : o.vector_of_referrables) { vector_of_referrables.emplace_back((v) ? new MyGame::Example::ReferrableT(*v) : nullptr); }
+  vector_of_weak_references.clear();
+  vector_of_weak_references.reserve(o.vector_of_weak_references.size());
+  for (const auto &v : o.vector_of_weak_references) { vector_of_weak_references.emplace_back(v); }
+  vector_of_strong_referrables.clear();
+  vector_of_strong_referrables.reserve(o.vector_of_strong_referrables.size());
+  for (const auto &v : o.vector_of_strong_referrables) { vector_of_strong_referrables.emplace_back((v) ? new MyGame::Example::ReferrableT(*v) : nullptr); }
+  vector_of_co_owning_references.clear();
+  vector_of_co_owning_references.reserve(o.vector_of_co_owning_references.size());
+  for (const auto &v : o.vector_of_co_owning_references) { vector_of_co_owning_references.emplace_back((v) ? new ReferrableT(*v) : nullptr); }
+  vector_of_non_owning_references.clear();
+  vector_of_non_owning_references.reserve(o.vector_of_non_owning_references.size());
+  for (const auto &v : o.vector_of_non_owning_references) { vector_of_non_owning_references.emplace_back(v); }
+  vector_of_enums.clear();
+  vector_of_enums.reserve(o.vector_of_enums.size());
+  for (const auto &v : o.vector_of_enums) { vector_of_enums.emplace_back(v); }
+
+  return *this;
+}
+
 inline MonsterT *Monster::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
   auto _o = std::make_unique<MonsterT>();
   UnPackTo(_o.get(), _resolver);
@@ -2590,7 +2765,7 @@ inline flatbuffers::Offset<void> AnyUnion::Pack(flatbuffers::FlatBufferBuilder &
 inline AnyUnion::AnyUnion(const AnyUnion &u) : type(u.type), value(nullptr) {
   switch (type) {
     case Any::Monster: {
-      FLATBUFFERS_ASSERT(false);  // MyGame::Example::MonsterT not copyable.
+      value = new MyGame::Example::MonsterT(*reinterpret_cast<MyGame::Example::MonsterT *>(u.value));
       break;
     }
     case Any::TestSimpleTableWithEnum: {
@@ -2701,7 +2876,7 @@ inline flatbuffers::Offset<void> AnyUniqueAliasesUnion::Pack(flatbuffers::FlatBu
 inline AnyUniqueAliasesUnion::AnyUniqueAliasesUnion(const AnyUniqueAliasesUnion &u) : type(u.type), value(nullptr) {
   switch (type) {
     case AnyUniqueAliases::M: {
-      FLATBUFFERS_ASSERT(false);  // MyGame::Example::MonsterT not copyable.
+      value = new MyGame::Example::MonsterT(*reinterpret_cast<MyGame::Example::MonsterT *>(u.value));
       break;
     }
     case AnyUniqueAliases::TS: {
@@ -2812,15 +2987,15 @@ inline flatbuffers::Offset<void> AnyAmbiguousAliasesUnion::Pack(flatbuffers::Fla
 inline AnyAmbiguousAliasesUnion::AnyAmbiguousAliasesUnion(const AnyAmbiguousAliasesUnion &u) : type(u.type), value(nullptr) {
   switch (type) {
     case AnyAmbiguousAliases::M1: {
-      FLATBUFFERS_ASSERT(false);  // MyGame::Example::MonsterT not copyable.
+      value = new MyGame::Example::MonsterT(*reinterpret_cast<MyGame::Example::MonsterT *>(u.value));
       break;
     }
     case AnyAmbiguousAliases::M2: {
-      FLATBUFFERS_ASSERT(false);  // MyGame::Example::MonsterT not copyable.
+      value = new MyGame::Example::MonsterT(*reinterpret_cast<MyGame::Example::MonsterT *>(u.value));
       break;
     }
     case AnyAmbiguousAliases::M3: {
-      FLATBUFFERS_ASSERT(false);  // MyGame::Example::MonsterT not copyable.
+      value = new MyGame::Example::MonsterT(*reinterpret_cast<MyGame::Example::MonsterT *>(u.value));
       break;
     }

@jfroy jfroy changed the title [C++] Support C++ object copies (#5783) [C++] Support C++ object copies Jun 19, 2020
@jfroy jfroy changed the title [C++] Support C++ object copies [C++] Support C++ object copies (fixes #5783) Jun 19, 2020
@jfroy jfroy changed the title [C++] Support C++ object copies (fixes #5783) [C++] Support C++ object copies Jun 19, 2020
Copy link
Collaborator

@aardappel aardappel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, cool feature! Did you run sh generate_code.sh ? I think there's some generated code files missing. Mention this in the C++ docs? We should have a section that documents what changes with the different C++ standard settings.
@vglavnyy

src/idl_gen_cpp.cpp Outdated Show resolved Hide resolved
src/idl_gen_cpp.cpp Outdated Show resolved Hide resolved
tests/cpp17/generated_cpp17/monster_test_generated.h Outdated Show resolved Hide resolved
tests/cpp17/generated_cpp17/monster_test_generated.h Outdated Show resolved Hide resolved
@jfroy
Copy link
Contributor Author

jfroy commented Jun 22, 2020

Thanks, cool feature! Did you run sh generate_code.sh ? I think there's some generated code files missing. Mention this in the C++ docs? We should have a section that documents what changes with the different C++ standard settings.
@vglavnyy

I did run generate_code.sh and the only modified file is tests/cpp17/generated_cpp17/monster_test_generated.h. By default, flatc runs in C++0X mode and thus most of the existing tests and generated files are not impacted by this patch.

Copy link
Contributor

@vglavnyy vglavnyy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good.
I need a few days to clone and test this PR locally.

src/idl_gen_cpp.cpp Outdated Show resolved Hide resolved
src/idl_gen_cpp.cpp Outdated Show resolved Hide resolved
@jfroy
Copy link
Contributor Author

jfroy commented Jun 23, 2020

Rebased and added code to emit a explicitly-defaulted default constructor for types that will have a copy/move ctor/assignment operator.

@vglavnyy
Copy link
Contributor

I've examined PR code.
Copying of unique_ptr looks a little bit confusing but I think it is normal for the Obj-API objects.

I think it would be better to use copy-swap for generated assignment operators. This pattern has strong guarantees against exceptions (commit-or-rollback).

Probably clear() call isn't necessary for copy constructors:

  testarrayofbools.clear(); // testarrayofbools is empty, it just constructed
  testarrayofbools.reserve(o.testarrayofbools.size());
  for (const auto &v : o.testarrayofbools) { testarrayofbools.emplace_back(v); }

Maybe add a template routine for the reserve-for-clone pattern into utils.h or flatbuffers.h?

template<class V>
void append_clone_of_vector(const V& from, V& to) {
 reserve()
 for(v : from) { to.emplace_back(...) }
}

@jfroy
Copy link
Contributor Author

jfroy commented Jul 1, 2020

Thanks for the feedback @vglavnyy . I'll get working on that next week after the break in the US.

@github-actions
Copy link

This pull request is stale because it has been open 6 months with no activity. Please comment or this will be closed in 14 days.

@github-actions github-actions bot added the stale label Dec 30, 2020
@catid
Copy link

catid commented Jan 8, 2021

This would be appreciated

catid added a commit to catid/flatbuffers that referenced this pull request Jan 8, 2021
catid added a commit to catid/flatbuffers that referenced this pull request Jan 8, 2021
@github-actions github-actions bot closed this Jan 22, 2021
@dbaileychess dbaileychess reopened this Jan 22, 2021
@aardappel
Copy link
Collaborator

@jfroy do you have time to finish this?

@jfroy
Copy link
Contributor Author

jfroy commented May 5, 2021

@jfroy do you have time to finish this?

Not immediately. I had to put this on hold, but I'll in fact have some free time in May. Maybe I can finish this up.

@OlivierLDff
Copy link
Contributor

Any news about this PR?
Would be very interested to reduce verbosity of my current copies of ObjectT

@google-cla
Copy link

google-cla bot commented Aug 11, 2021

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed (or fixed any issues), please reply here with @googlebot I signed it! and we'll verify it.


What to do if you already signed the CLA

Individual signers
Corporate signers

ℹ️ Googlers: Go here for more info.

@github-actions github-actions bot added c++ codegen Involving generating code from schema labels Aug 11, 2021
@jfroy
Copy link
Contributor Author

jfroy commented Aug 11, 2021

I've examined PR code.
Copying of unique_ptr looks a little bit confusing but I think it is normal for the Obj-API objects.

I think it would be better to use copy-swap for generated assignment operators. This pattern has strong guarantees against exceptions (commit-or-rollback).

Probably clear() call isn't necessary for copy constructors:

  testarrayofbools.clear(); // testarrayofbools is empty, it just constructed
  testarrayofbools.reserve(o.testarrayofbools.size());
  for (const auto &v : o.testarrayofbools) { testarrayofbools.emplace_back(v); }

Maybe add a template routine for the reserve-for-clone pattern into utils.h or flatbuffers.h?

template<class V>
void append_clone_of_vector(const V& from, V& to) {
 reserve()
 for(v : from) { to.emplace_back(...) }
}

I've updated the PR to use copy-and-swap. I did not switch to a helper function for vector cloning because it didn't seem worth it and raised some annoying namespace issues.

@jfroy
Copy link
Contributor Author

jfroy commented Aug 11, 2021

Improved the generator a bit to use std::vector's copy constructor for non-pointer element types. This allows more efficient copies for trivially-copyable element types (where an implementation may do a memcpy). This also deals with std::vector<bool> (🙄).

Not sure why CI / Build Kotlin is unhappy.

@jfroy
Copy link
Contributor Author

jfroy commented Aug 11, 2021

Any news about this PR?
Would be very interested to reduce verbosity of my current copies of ObjectT

Thanks for, huh, encouraging me to try to finish this.

@OlivierLDff
Copy link
Contributor

Not sure why CI / Build Kotlin is unhappy.

Seems that it is the same in master

Thanks for the work!

@aardappel
Copy link
Collaborator

@vglavnyy this look good to you now?

@krojew @paulovap seems Kotlin is still broken due to the Java 8 related changes, what do we do about this?

@krojew
Copy link
Contributor

krojew commented Aug 13, 2021

@aardappel I don't know Kotlin, so I can't help much there.

Also, what is the semantics of copying tables? Does it simply copy references? If so, it can lead to a strange situation with mutating API, when mutating a single copy, mutates every copy.

@jfroy
Copy link
Contributor Author

jfroy commented Aug 13, 2021

Also, what is the semantics of copying tables? Does it simply copy references? If so, it can lead to a strange situation with mutating API, when mutating a single copy, mutates every copy.

Table objects are deep-copied recursively. In other words, they act as value types. Any other semantic, as you point out, is broken.

@aardappel
Copy link
Collaborator

@krojew isn't Kotlin failing on your Java changes though? Or am I not understanding correctly?

They both run on the same JVM and are subject to the same object/casting rules, so I wouldn't think it's so different :)

@krojew
Copy link
Contributor

krojew commented Aug 13, 2021

@aardappel technically yes, but I have no idea why. It's complaining about missing symbols which do exist when using Java, so it's something kotlin specific.

@paulovap
Copy link
Collaborator

paulovap commented Aug 13, 2021

@krojew isn't Kotlin failing on your Java changes though? Or am I not understanding correctly?

They both run on the same JVM and are subject to the same object/casting rules, so I wouldn't think it's so different :)

I will have some time to check whats going on with Kotlin tomorrow.

Edit: I took a look and the issue is that with @krojew changes its no longer possible to use Java 8 compiler to build the java source code. I just updated CI to use Java 11, while it still emits Java 8 bytecode.

I believe #6764 should be enough to fix the original issue that @krojew tried to fix, so his changes are no longer necessary, but this is something we can revert afterwards

Fix is in #6783

@bjornharrtell
Copy link
Collaborator

@paulovap I think you are right and I've created a PR with the revert of those changes here #6785.

@dbaileychess
Copy link
Collaborator

Like to ping this again to see if we can get it in.

@jfroy
Copy link
Contributor Author

jfroy commented Sep 22, 2021

I thought it was ready to go and waiting for review, but it seems some old Visual Studio versions have problems in CI. I'll try to spend time soon to address those.

@dbaileychess
Copy link
Collaborator

@jfory CI might be better now that we have drop support for VS2010. Mind updating?

@jfroy
Copy link
Contributor Author

jfroy commented Dec 13, 2021

@jfory CI might be better now that we have drop support for VS2010. Mind updating?

Thanks for the ping. I rebased and looks like CI is now green. I was hoping to get the time to rework the patch to deal with (very) old compiler toolchains, but looks like I won't have to.

@dbaileychess
Copy link
Collaborator

Ok, thanks! I'll take one more review tonight and try to get it in.

@dbaileychess
Copy link
Collaborator

It looks good to me, though we should add some tests.

@jfroy
Copy link
Contributor Author

jfroy commented Dec 16, 2021

It looks good to me, though we should add some tests.

I've added a basic copy test by extending ObjectFlatBuffersTest.

Augment the C++ generator to emit a C++ copy constructor and a by-value
copy assignment operator. This is enabled by default when the C++
standard is C++11 or later. These additional functions are only emitted
for objects that need it, typically tables containing other tables.

These new functions are declared in the object table type and are
defined as inline functions after table declarations.

When these new functions are declared, a user-defined
explicitly-defaulted default constructor and move constructor are also
emitted.

The copy assignment operator uses the copy-and-swap idiom to provide
strong exception safety, at the expense of keeping 2 full table copies
in memory temporarily.

fixes #5783
@dbaileychess
Copy link
Collaborator

Sorry for the delay, looks good and thanks for adding the test.

Anything pending or can I submit?

@jfroy
Copy link
Contributor Author

jfroy commented Jan 29, 2022

Sorry for the delay, looks good and thanks for adding the test.

Anything pending or can I submit?

Nope good to go.

@dbaileychess dbaileychess merged commit 4320398 into google:master Jan 29, 2022
@dbaileychess
Copy link
Collaborator

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ codegen Involving generating code from schema
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants