public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* RE: Question on move constructor
@ 2013-01-29 15:48 Graziano Servizi
  0 siblings, 0 replies; 8+ messages in thread
From: Graziano Servizi @ 2013-01-29 15:48 UTC (permalink / raw)
  To: gcc-help

 > I'm sorry; I made a mistake: it was the DESTRUCTOR (which IS 
provided) that
 > needed to be noexcept-ed. On my system, if I didn't so, there are
 > 3 moves and 3 copies (as you said), while with a noexcept DESTRUCTOR 
no copy
 > occurs: only 6 moves.

Ah yes, with GCC 4.7 that is necessary.

I was testing with GCC trunk which has implicit noexcept on
destructors (as required by C++11)


OK, all is fine!
        GS

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Question on move constructor
  2013-01-28 18:29 Graziano Servizi
@ 2013-01-28 19:51 ` Jonathan Wakely
  0 siblings, 0 replies; 8+ messages in thread
From: Jonathan Wakely @ 2013-01-28 19:51 UTC (permalink / raw)
  To: Graziano Servizi; +Cc: gcc-help

On 28 January 2013 18:16, Graziano Servizi <Graziano.Servizi@bo.infn.it> wrote:
>> However specifying "noexcept" turns out to be necessary at least for the
>> default constructor, otherwise no "move" operation is performed (on my
>> system). Saying this I refer to the code I sent you in my early message.
>> May be this is due to the instantiation of "v" in the first line of main?
>> Did you ever meet such a situation before?
>
> No, I don't see how it's possible.
> The code in your first message has no default constructor, so I don't
> understand how making a non-existent constructor noexcept can change
> anything!
>
>
> I'm sorry; I made a mistake: it was the DESTRUCTOR (which IS provided) that
> needed to be noexcept-ed. On my system, if I didn't so, there are
> 3 moves and 3 copies (as you said), while with a noexcept DESTRUCTOR no copy
> occurs: only 6 moves.

Ah yes, with GCC 4.7 that is necessary.

I was testing with GCC trunk which has implicit noexcept on
destructors (as required by C++11)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: Question on move constructor
@ 2013-01-28 18:29 Graziano Servizi
  2013-01-28 19:51 ` Jonathan Wakely
  0 siblings, 1 reply; 8+ messages in thread
From: Graziano Servizi @ 2013-01-28 18:29 UTC (permalink / raw)
  To: gcc-help

 > However specifying "noexcept" turns out to be necessary at least for the
 > default constructor, otherwise no "move" operation is performed (on my
 > system). Saying this I refer to the code I sent you in my early message.
 > May be this is due to the instantiation of "v" in the first line of main?
 > Did you ever meet such a situation before?

No, I don't see how it's possible.
The code in your first message has no default constructor, so I don't
understand how making a non-existent constructor noexcept can change
anything!


I'm sorry; I made a mistake: it was the DESTRUCTOR (which IS provided) 
that needed to be noexcept-ed. On my system, if I didn't so, there are
3 moves and 3 copies (as you said), while with a noexcept DESTRUCTOR no 
copy occurs: only 6 moves.

                                   GS

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Question on move constructor
  2013-01-28 17:28 Graziano Servizi
@ 2013-01-28 18:17 ` Jonathan Wakely
  0 siblings, 0 replies; 8+ messages in thread
From: Jonathan Wakely @ 2013-01-28 18:17 UTC (permalink / raw)
  To: Graziano Servizi; +Cc: gcc-help

On 28 January 2013 17:13, Graziano Servizi wrote:
>
> However specifying "noexcept" turns out to be necessary at least for the
> default constructor, otherwise no "move" operation is performed (on my
> system). Saying this I refer to the code I sent you in my early message.
> May be this is due to the instantiation of "v" in the first line of main?
> Did you ever meet such a situation before?

No, I don't see how it's possible.
The code in your first message has no default constructor, so I don't
understand how making a non-existent constructor noexcept can change
anything!

In the file "my_output.txt" you showed move operations like this one:

In MemoryBlock(MemoryBlock&&). length = 25. Moving resource.

If I run that code I get the same output, three moves, three copies.
If I add 'noexcept' to the move constructor and move assignment
operator then I get six moves and no copies.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: Question on move constructor
@ 2013-01-28 17:28 Graziano Servizi
  2013-01-28 18:17 ` Jonathan Wakely
  0 siblings, 1 reply; 8+ messages in thread
From: Graziano Servizi @ 2013-01-28 17:28 UTC (permalink / raw)
  To: gcc-help

 > I had to give, however, the noexcept specifier not only to the "move"
 > functions, but to the copy constructor and copy assignment operator 
as well.

That should not be necessary, and is wrong because the copy
constructor allocates memory and so can throw exceptions.



However specifying "noexcept" turns out to be necessary at least for the
default constructor, otherwise no "move" operation is performed (on my 
system). Saying this I refer to the code I sent you in my early message.
May be this is due to the instantiation of "v" in the first line of 
main? Did you ever meet such a situation before?


The rest of my questions are fully answered.

Thanks.

                            GS


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Question on move constructor
  2013-01-28 14:48 ` Jonathan Wakely
@ 2013-01-28 15:14   ` Jonathan Wakely
  0 siblings, 0 replies; 8+ messages in thread
From: Jonathan Wakely @ 2013-01-28 15:14 UTC (permalink / raw)
  To: Graziano Servizi; +Cc: gcc-help

On 28 January 2013 14:46, Jonathan Wakely wrote:
> On 28 January 2013 14:35, Graziano Servizi wrote:
>>
>> WHEN are they called?
>
> This is not the right list for answering that, as it's not a question about GCC.
>
> They're called when constructing from an rvalue.
>
>> I got an example on Internet (attached) and the output they claim to be
>> obtained (also attached) is NOT reproduced on my system (it is attached as
>> well).
>>
>> I also tried some checks of my own and I was unable to call a move
>> constructor that I wrote in my classes (I presume in a correct way, since
>> the compiler didn't complain). It seems to me that, anytime the standard
>> 2011 claims that a move constructor should be called, the "classical" copy
>> constructor is called instead, unless one explicitly use a call to the
>> std::move function. Is this correct or wrong?
>
> I can't comment on your own tests, but in the sample_code.C program
> you attached the std::vector operations do not move the elements
> because your move constructor and move assignment operator can throw
> exceptions.

To be more precise, the library code cannot prove they will not throw
exceptions, so it assumes they might throw.

To inform the library they will not throw, add the "noexcept"
specifier to the move functions, so that std::vector knows it is safe
to move the objects.

>  The std::vector implementation in libstdc++ will only
> move elements if doing so is guaranteed not to throw exceptions,
> otherwise there could be data loss and the vector contents could be
> left in an inconsistent state.
>
> To ensure your class gets moved, make your move operations "noexcept"

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Question on move constructor
  2013-01-28 14:46 Graziano Servizi
@ 2013-01-28 14:48 ` Jonathan Wakely
  2013-01-28 15:14   ` Jonathan Wakely
  0 siblings, 1 reply; 8+ messages in thread
From: Jonathan Wakely @ 2013-01-28 14:48 UTC (permalink / raw)
  To: Graziano Servizi; +Cc: gcc-help

On 28 January 2013 14:35, Graziano Servizi wrote:
>
> WHEN are they called?

This is not the right list for answering that, as it's not a question about GCC.

They're called when constructing from an rvalue.

> I got an example on Internet (attached) and the output they claim to be
> obtained (also attached) is NOT reproduced on my system (it is attached as
> well).
>
> I also tried some checks of my own and I was unable to call a move
> constructor that I wrote in my classes (I presume in a correct way, since
> the compiler didn't complain). It seems to me that, anytime the standard
> 2011 claims that a move constructor should be called, the "classical" copy
> constructor is called instead, unless one explicitly use a call to the
> std::move function. Is this correct or wrong?

I can't comment on your own tests, but in the sample_code.C program
you attached the std::vector operations do not move the elements
because your move constructor and move assignment operator can throw
exceptions.  The std::vector implementation in libstdc++ will only
move elements if doing so is guaranteed not to throw exceptions,
otherwise there could be data loss and the vector contents could be
left in an inconsistent state.

To ensure your class gets moved, make your move operations "noexcept"

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Question on move constructor
@ 2013-01-28 14:46 Graziano Servizi
  2013-01-28 14:48 ` Jonathan Wakely
  0 siblings, 1 reply; 8+ messages in thread
From: Graziano Servizi @ 2013-01-28 14:46 UTC (permalink / raw)
  To: gcc-help

[-- Attachment #1: Type: text/plain, Size: 918 bytes --]

Hi,

My name is Graziano Servizi, Associate Professor in Mathematical Physics 
at Bologna University, Italy.

I'm using release 4.7.2 of GNU-GCC on a Fedora 17 Linux System.

I would ask you a question about move constructors, namely

WHEN are they called?

I got an example on Internet (attached) and the output they claim to be 
obtained (also attached) is NOT reproduced on my system (it is attached 
as well).

I also tried some checks of my own and I was unable to call a move 
constructor that I wrote in my classes (I presume in a correct way, 
since the compiler didn't complain). It seems to me that, anytime the 
standard 2011 claims that a move constructor should be called, the 
"classical" copy constructor is called instead, unless one explicitly 
use a call to the std::move function. Is this correct or wrong?


Answers are kindly requested and welcome.

                             Graziano Servizi


[-- Attachment #2: sample_code.C --]
[-- Type: text/x-c++src, Size: 3157 bytes --]

// found on http://msdn.microsoft.com/en-us/library/dd293665.aspx

// MemoryBlock.h
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

class MemoryBlock
{
public:

   // Simple constructor that initializes the resource.
   explicit MemoryBlock(size_t length)
      : _length(length)
      , _data(new int[length])
   {
      cout << "In MemoryBlock(size_t). length = "
                << _length << "." << endl;
   }

   // Destructor.
   ~MemoryBlock()
   {
      cout << "In ~MemoryBlock(). length = "
                << _length << ".";
      
      if (_data != NULL)
      {
         cout << " Deleting resource.";
         // Delete the resource.
         delete[] _data;
      }

      cout << endl;
   }

   // Copy constructor.
   MemoryBlock(const MemoryBlock& other)
      : _length(other._length)
      , _data(new int[other._length])
   {

      cout << "In MemoryBlock(const MemoryBlock&). length = " 
                << other._length << ". Copying resource." << endl;

      copy(other._data, other._data + _length, _data);
   }

   // Copy assignment operator.
   MemoryBlock& operator=(const MemoryBlock& other)
   {
      cout << "In operator=(const MemoryBlock&). length = " 
                << other._length << ". Copying resource." << endl;

      if (this != &other)
      {
         // Free the existing resource.
         delete[] _data;

         _length = other._length;
         _data = new int[_length];
         copy(other._data, other._data + _length, _data);
      }
      return *this;
   }

   // Retrieves the length of the data resource.
   size_t Length() const
   {
      return _length;
   }


// Move constructor.
MemoryBlock(MemoryBlock&& other)
   : _data(NULL)
   , _length(0)
{

   cout << "In MemoryBlock(MemoryBlock&&). length = " 
             << other._length << ". Moving resource." << endl;

   // Copy the data pointer and its length from the 
   // source object.
   _data = other._data;
   _length = other._length;

   // Release the data pointer from the source object so that
   // the destructor does not free the memory multiple times.
   other._data = NULL;
   other._length = 0;
}

// Move assignment operator.
MemoryBlock& operator=(MemoryBlock&& other)
{
   cout << "In operator=(MemoryBlock&&). length = " 
             << other._length << "." << endl;

   if (this != &other)
   {
      // Free the existing resource.
      delete[] _data;

      // Copy the data pointer and its length from the 
      // source object.
      _data = other._data;
      _length = other._length;

      // Release the data pointer from the source object so that
      // the destructor does not free the memory multiple times.
      other._data = NULL;
      other._length = 0;
   }
   return *this;
}

private:
   size_t _length; // The length of the resource.
   int* _data; // The resource.
};





int main()
{
   // Create a vector object and add a few elements to it.
   vector<MemoryBlock> v;
   v.push_back(MemoryBlock(25));
   v.push_back(MemoryBlock(75));

   // Insert a new element into the second position of the vector.
   v.insert(v.begin() + 1, MemoryBlock(50));
}



[-- Attachment #3: their_output --]
[-- Type: text/plain, Size: 809 bytes --]

In MemoryBlock(size_t). length = 25.
In MemoryBlock(MemoryBlock&&). length = 25. Moving resource.
In ~MemoryBlock(). length = 0.
In MemoryBlock(size_t). length = 75.
In MemoryBlock(MemoryBlock&&). length = 25. Moving resource.
In ~MemoryBlock(). length = 0.
In MemoryBlock(MemoryBlock&&). length = 75. Moving resource.
In ~MemoryBlock(). length = 0.
In MemoryBlock(size_t). length = 50.
In MemoryBlock(MemoryBlock&&). length = 50. Moving resource.
In MemoryBlock(MemoryBlock&&). length = 50. Moving resource.
In operator=(MemoryBlock&&). length = 75.
In operator=(MemoryBlock&&). length = 50.
In ~MemoryBlock(). length = 0.
In ~MemoryBlock(). length = 0.
In ~MemoryBlock(). length = 25. Deleting resource.
In ~MemoryBlock(). length = 50. Deleting resource.
In ~MemoryBlock(). length = 75. Deleting resource.


[-- Attachment #4: my_output --]
[-- Type: text/plain, Size: 894 bytes --]

In MemoryBlock(size_t). length = 25.
In MemoryBlock(MemoryBlock&&). length = 25. Moving resource.
In ~MemoryBlock(). length = 0.
In MemoryBlock(size_t). length = 75.
In MemoryBlock(MemoryBlock&&). length = 75. Moving resource.
In MemoryBlock(const MemoryBlock&). length = 25. Copying resource.
In ~MemoryBlock(). length = 25. Deleting resource.
In ~MemoryBlock(). length = 0.
In MemoryBlock(size_t). length = 50.
In MemoryBlock(MemoryBlock&&). length = 50. Moving resource.
In MemoryBlock(const MemoryBlock&). length = 25. Copying resource.
In MemoryBlock(const MemoryBlock&). length = 75. Copying resource.
In ~MemoryBlock(). length = 25. Deleting resource.
In ~MemoryBlock(). length = 75. Deleting resource.
In ~MemoryBlock(). length = 0.
In ~MemoryBlock(). length = 25. Deleting resource.
In ~MemoryBlock(). length = 50. Deleting resource.
In ~MemoryBlock(). length = 75. Deleting resource.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2013-01-29 15:05 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-29 15:48 Question on move constructor Graziano Servizi
  -- strict thread matches above, loose matches on Subject: below --
2013-01-28 18:29 Graziano Servizi
2013-01-28 19:51 ` Jonathan Wakely
2013-01-28 17:28 Graziano Servizi
2013-01-28 18:17 ` Jonathan Wakely
2013-01-28 14:46 Graziano Servizi
2013-01-28 14:48 ` Jonathan Wakely
2013-01-28 15:14   ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).