Emplace question

B

Brian

In this thread,
http://groups.google.com/group/comp.lang.c++/browse_thread/thread/f4a8b07d4aa18d73#

I recently posted this:

template <typename B>
void
Receive(B* buf, vector<deque<lil_string> >& abt1)
{
uint32_t headCount[2];
buf->Give(headCount[0]);
abt1.reserve(abt1.size() + headCount[0]);
for (; headCount[0] > 0; --headCount[0]) {
deque<lil_string> rep4;
buf->Give(headCount[1]);
for (; headCount[1] > 0; --headCount[1]) {
lil_string rep5(buf);
rep4.push_back(std::move(rep5));
}
abt1.push_back(std::move(rep4));
}
}

I have a question related to the inner loop and emplace. I thought
the correct way to do things would be like this:

for (; headCount[1] > 0; --headCount[1]) {
rep4.emplace_back(buf);
}

However, some documentation I read --
http://msdn.microsoft.com/en-us/library/dd647620.aspx

suggests that it should be:
for (; headCount[1] > 0; --headCount[1]) {
rep4.emplace_back(lil_string(buf));
}

I'm not sure if both are considered correct or just one is.
Does the latter approach try to use a lil_string move
constructor? I thought emplace (in the former snippet)
would efficiently add an object to the container even if
the type doesn't have a move constructor. That seems
like a big advantage to me. Thanks in advance.


Brian Wood
http://webEbenezer.net
(651) 251-9384
 
T

Thomas J. Gritzan

Am 17.05.2010 21:34, schrieb Brian:
In this thread,
http://groups.google.com/group/comp.lang.c++/browse_thread/thread/f4a8b07d4aa18d73#

I recently posted this:

template <typename B>
void
Receive(B* buf, vector<deque<lil_string> >& abt1)
{
uint32_t headCount[2];
buf->Give(headCount[0]);
abt1.reserve(abt1.size() + headCount[0]);
for (; headCount[0] > 0; --headCount[0]) {
deque<lil_string> rep4;
buf->Give(headCount[1]);
for (; headCount[1] > 0; --headCount[1]) {
lil_string rep5(buf);
rep4.push_back(std::move(rep5));
}
abt1.push_back(std::move(rep4));
}
}

I have a question related to the inner loop and emplace. I thought
the correct way to do things would be like this:

for (; headCount[1] > 0; --headCount[1]) {
rep4.emplace_back(buf);
}

It's correct. It constructs a lil_string as new element of rep4, using
buf as first parameter. The parameter is perfectly forwarded to
lil_string's constructor.
However, some documentation I read --
http://msdn.microsoft.com/en-us/library/dd647620.aspx

suggests that it should be:
for (; headCount[1] > 0; --headCount[1]) {
rep4.emplace_back(lil_string(buf));
}

I'm not sure if both are considered correct or just one is.

Also correct. It constructs a lil_string and copy-constructs (or moves)
it to the new element of rep4.
Visual C++ doesn't yet correctly implement emplace_back because they
don't have variadic templates in the compiler, so in both cases the new
element is copied or moved into the container, if you use VC++.
Does the latter approach try to use a lil_string move
constructor?

Both call the copy or move constructor with this compiler, unless they
are optimized away.
However, the intend was that the first snippet doesn't copy or move the
elements.
I thought emplace (in the former snippet)
would efficiently add an object to the container even if
the type doesn't have a move constructor. That seems
like a big advantage to me. Thanks in advance.

If your tool has a C++2003 mode, you could swap some elements into the
containers to simulate move construction:

deque<lil_string> rep4;
buf->Give(headCount[1]);
for (; headCount[1] > 0; --headCount[1]) {
lil_string rep5(buf);
// swap rep5 to the end of rep4
rep4.push_back( lil_string() );
rep4.back().swap(rep5); // if lil_string has a swap
}
// swap rep4 into its final location
abt1.push_back( deque<lil_string>() );
abt1.back().swap(rep4);

This surely is faster than copying everything into its container and
might even be as fast as the std::move version.
 
B

Brian

Am 17.05.2010 21:34, schrieb Brian:


I recently posted this:
 template <typename B>
 void
 Receive(B* buf, vector<deque<lil_string> >& abt1)
 {
   uint32_t headCount[2];
   buf->Give(headCount[0]);
   abt1.reserve(abt1.size() + headCount[0]);
   for (; headCount[0] > 0; --headCount[0]) {
     deque<lil_string> rep4;
     buf->Give(headCount[1]);
     for (; headCount[1] > 0; --headCount[1]) {
       lil_string rep5(buf);
       rep4.push_back(std::move(rep5));
     }
     abt1.push_back(std::move(rep4));
   }
 }
I have a question related to the inner loop and emplace.  I thought
the correct way to do things would be like this:
  for (; headCount[1] > 0; --headCount[1]) {
     rep4.emplace_back(buf);
  }

It's correct. It constructs a lil_string as new element of rep4, using
buf as first parameter. The parameter is perfectly forwarded to
lil_string's constructor.
suggests that it should be:
   for (; headCount[1] > 0; --headCount[1]) {
     rep4.emplace_back(lil_string(buf));
   }
I'm not sure if both are considered correct or just one is.

Also correct. It constructs a lil_string and copy-constructs (or moves)
it to the new element of rep4.
Visual C++ doesn't yet correctly implement emplace_back because they
don't have variadic templates in the compiler, so in both cases the new
element is copied or moved into the container, if you use VC++.


OK, that makes sense.

If your tool has a C++2003 mode, you could swap some elements into the
containers to simulate move construction:

   deque<lil_string> rep4;
   buf->Give(headCount[1]);
   for (; headCount[1] > 0; --headCount[1]) {
      lil_string rep5(buf);
      // swap rep5 to the end of rep4
      rep4.push_back( lil_string() );
      rep4.back().swap(rep5); // if lil_string has a swap
   }
   // swap rep4 into its final location
   abt1.push_back( deque<lil_string>() );
   abt1.back().swap(rep4);

That's a good point. I'm thinking about using that any time
there are nested containers for both 2003 and C++0x -- rather
than introducing a C++2003 mode. At the innermost level it
would still either copy or move the objects. Someone else
recently suggested using swaps in the Receive code to have
roll-back exception safety.
This surely is faster than copying everything into its container and
might even be as fast as the std::move version.

I guess that's right. It's too bad I didn't think about this
several years ago... better late than never.


Brian Wood
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,930
Messages
2,570,072
Members
46,521
Latest member
JamieCooch

Latest Threads

Top