Moving an inserted container item, if possible

I am trying to do the following optimization in my container library:

  • when pasting an element with a link to lvalue, copy it to internal memory;
  • but when you insert an element with a link to rvalue, move it if it is supported.

Optimization should be useful, for example. if the type of the element with the content is similar to std::vectorwhere moving, if possible, will give significant acceleration.

However, so far I have not been able to develop any working scheme for this. My container is quite complex, so I can’t just duplicate the code insert()several times: it is big. I want to save all the "real" code in some kind of internal helper, say do_insert()(maybe a template), and various insert()-like functions will just call it with different arguments.

My best code for this (prototype, of course, without doing anything real):

#include <iostream>
#include <utility>

struct element
{
  element () { };
  element (element&&) { std::cerr << "moving\n"; }
};

struct container
{
  void  insert (const element& value)
  {  do_insert (value);  }

  void  insert (element&& value)
  {  do_insert (std::move (value));  }

private:
  template <typename Arg>
  void  do_insert (Arg arg)
  {  element  x (arg);  }
};

int
main ()
{
  {
    // Shouldn't move.
    container  c;
    element x;
    c.insert (x);
  }

  {
    // Should move.
    container  c;
    c.insert (element ());
  }
}

However, this does not work, at least with GCC 4.4 and 4.5: it never prints a "move" to stderr. Or what can I not achieve, and why do emplace()similar functions exist in the first place?

+3
source share
3

, :

  template <typename Arg>
  void  do_insert (Arg&& arg)
  {  element  x (std::forward<Arg>(arg));  }

:

#include <iostream>
#include <utility>

struct element
{
  element () { };
  element (const element&) { std::cerr << "copying\n"; }
  element (element&&) { std::cerr << "moving\n"; }
};

struct container
{
  void  insert (const element& value)
  {  do_insert (value);  }

  void  insert (element&& value)
  {  do_insert (std::move(value));  }

private:
  template <typename Arg>
  void  do_insert (Arg&& arg)
  {  element  x (std::forward<Arg>(arg));  }
};

int
main ()
{
  {
    // Shouldn't move.
    container  c;
    element x;
    c.insert (x);
  }
  {
    // Should move.
    container  c;
    c.insert (element ());
  }
}

, , " ".

+2

, STL ( GNU, ).

  template <typename Arg>
  void  do_insert (Arg arg)
  {  element  x (move(arg));  }

.

emplace, , .

EDIT

  • ,
  • move, . , ... .

.

#include <iostream>
#include <utility>

struct element
{
  element () : moved(false) { };
  element (element&&) { moved = true; std::cerr << "moving\n"; }
  bool moved;
};

struct container
{
  void  insert (const element& value)
  {  do_insert (value);  }

  void  insert (element&& value)
  {  do_insert (std::move (value));  }

private:
  template <typename Arg>
  void  do_insert (Arg arg)
  {  element  x (std::move(arg));  }
};

int
main ()
{
  std::cerr << "try 1\n";
  {
    // Shouldn't move.
    container  c;
    element x;
    c.insert (x);
    std::cerr << x.moved << "\n";
  }

  std::cerr << "try 2\n";
  {
    // Should move.
    container  c;
    c.insert (element ());
  }
}
0

I can’t say that I understand why this works, and some other code doesn’t, but it seems to do the trick (created thanks to tips from Potatoswatter):

#include <iostream>
#include <utility>

struct element
{
  element () { };
  element (const element&) { std::cerr << "copying\n"; }
  element (element&&) { std::cerr << "moving\n"; }
};

struct container
{
  void  insert (const element& value)
  {  do_insert <const element&> (value);  }

  void  insert (element&& value)
  {  do_insert <element&&> (std::forward <element&&> (value));  }

private:
  template <typename Arg>
  void  do_insert (Arg arg)
  {  element  x (std::forward <Arg> (arg));  }
};

int
main ()
{
  std::cerr << "1\n";
  {
    // Shouldn't move.
    container  c;
    element x;
    c.insert (x);
  }

  std::cerr << "2\n";
  {
    // Should move.
    container  c;
    c.insert (element ());
  }
}

I get the following output with both GCC 4.4 and 4.5:

1
copying
2
moving
0
source

Source: https://habr.com/ru/post/1742582/


All Articles