0

I am using the CGAL library and writing a function that I hope to use move semantics as described in this question:

PointTree preparePointTree(const vector<PlyPoint>& pointCloud) {
  PointTree tree;
  kd_tree::prepare<...>(pointCloud, tree);
  return tree;
}

and I'm calling it like:

PointTree tree = preparePointTree(pointCloud);

Unfortunately, it does not compile; GCC complains that:

return tree;  // <-- error: 'CGAL::Kd_tree<...>' is private within this context

with note:

private:
  // protected copy constructor
  Kd_tree(const Tree& tree)   // <-- note: declared private here

which is from this code.

So the issue seems to be that returning tree is illegal if the copy-constructor is unavailable, even though I don't want to copy, but to move.

I suppose that's because because move semantics depend on the call site (the call to preparePointTree()), and the function implementation by itself is treated as "has to compile even in the non-move case".

So, what now?

Is there something that I, or the CGAL library, can do to allow moving but not copying?

What's the reasoning behind this?

nh2
  • 24,526
  • 11
  • 79
  • 128
  • Can you pass the return value in as a second argument and do an explicit move? – Anon Mail Sep 15 '21 at 20:54
  • 3
    But the `kd_tree` doesn't support moving at all. Wrap it via `unique_ptr` or something. – ALX23z Sep 15 '21 at 20:59
  • 1
    *"even though I don't want to copy, but to move"* - it does try to move. But there is no move constructor provided by `Kd_tree`, and its automatic generation is inhibited by the user-declared copy c'tor. This class is not meant to be passed around as it seems. Try indirection. – StoryTeller - Unslander Monica Sep 15 '21 at 20:59
  • 1
    i suppose the actual error message doesnt say " error: 'CGAL::Kd_tree<...>' is private within this context" but rather `CGAL::Kd_tree<...>(CGAL::Kd_tree&)` or similar – 463035818_is_not_an_ai Sep 15 '21 at 21:01
  • @463035818_is_not_a_number You are correct, expanding my shortening, it is `CGAL::Kd_tree<...>::Kd_tree(const Tree&) [with ...2000 more chars...]`. – nh2 Sep 15 '21 at 22:26

1 Answers1

0

From cppreference on move constructors:

If no user-defined move constructors are provided for a class type (struct, class, or union), and all of the following is true:

  • there are no user-declared copy constructors;
  • there are no user-declared copy assignment operators;
  • there are no user-declared move assignment operators;
  • there is no user-declared destructor.

then the compiler will declare a move constructor as a non-explicit inline public member of its class with the signature T::T(T&&).

The Kd_tree class provides a user-declared copy constructor, so it doesn't get a move constructor automatically. Since it doesn't have a move constructor you cannot move it.

Kevin
  • 6,993
  • 1
  • 15
  • 24
  • 2
    You can "move" things without a move c'tor. The copy c'tor can serve that purpose. But it must be accessible. – StoryTeller - Unslander Monica Sep 15 '21 at 21:02
  • What do you mean by "move" things (in quotes)? (N)RVO, which just elides the copy/move altogether? – Kevin Sep 15 '21 at 21:09
  • @Kevin a move of something that cannot move but can copy is just a copy – 463035818_is_not_an_ai Sep 15 '21 at 21:13
  • 2
    The provision of a return statement returning a local is to first treat it as an rvalue, then (if overload resolution fails) treat it as an lvalue. This always happens, regardless of NRVO. The const reference of the copy c'tor can bind to an rvalue, and so it will be used when no move c'tor is generated. Hence the quotes. It's moved successfully, but by copying. – StoryTeller - Unslander Monica Sep 15 '21 at 21:14