9

I'm doing an exercise from C++ Primer 5th Edition, which goes like:

Exercise 13.50: Put print statements in the move operations in your String class and rerun the program from exercise 13.48 in § 13.6.1 (p. 534) that used a vector to see when the copies are avoided.(P.544)

The String is a class for practise which behaves like a std::string without using any template. The String.h file:

class String
{
public:
    //! default constructor
    String();

    //! constructor taking C-style string i.e. a char array terminated with'\0'.
    explicit String(const char * const c);

    //! copy constructor
    explicit String(const String& s);

    //! move constructor    
    String(String&& s) noexcept;

    //! operator =
    String& operator = (const String& rhs);

    //! move operator =     
    String& operator = (String&& rhs) noexcept;

    //! destructor
    ~String();

    //! members
    char* begin() const  { return elements;   }
    char* end()   const  { return first_free; }

    std::size_t size()     const {return first_free - elements;  }
    std::size_t capacity() const {return cap - elements;         }

private:

    //! data members
    char* elements;
    char* first_free;
    char* cap;

    std::allocator<char> alloc;

    //! utillities for big 3
    void free();

};

Implementation for default, copy and move constructor from String.cpp :

//! default constructor
String::String():
    elements    (nullptr),
    first_free  (nullptr),
    cap         (nullptr)
{}

//! copy constructor
String::String(const String &s)
{
    char* newData = alloc.allocate(s.size());
    std::uninitialized_copy(s.begin(), s.end(), newData);

    elements = newData;
    cap = first_free = newData + s.size();

    std::cout << "Copy constructing......\n";
}

//! move constructor    
String::String(String &&s) noexcept :
    elements(s.elements), first_free(s.first_free), cap(s.cap)
{
    s.elements = s.first_free = s.cap = nullptr;
    std::cout << "Move constructing......\n";
}

Main.cpp:

int main()
{
    std::vector<String> v;
    String s;
    for (unsigned i = 0; i != 4; ++i)
        v.push_back(s);

    return 0;
}

The output:

Copy constructing......
Copy constructing......
Copy constructing......
Copy constructing......
Copy constructing......
Copy constructing......
Copy constructing......

As can be seen, the move constructor was not called at all. Why wasn't the move constructor called when the vector allocating more memory?

Update:

The info of compiler:

gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-1ubuntu1) 

main.cpp with printing capacity and its ouput:

int main()
{
    std::vector<String> v;
    String s;
    for (unsigned i = 0; i != 4; ++i)
    {
        std::cout << v.capacity() << "\n";
        v.push_back(s);
    }

    return 0;
}

Output:

0
Copy constructing......
1
Copy constructing......
Copy constructing......
2
Copy constructing......
Copy constructing......
Copy constructing......
4
Copy constructing......
Johan
  • 3,728
  • 16
  • 25
Yue Wang
  • 1,710
  • 3
  • 18
  • 43
  • 2
    [Works for me](http://ideone.com/9YaaZ0), once I add enough of the missing definitions for it to compile. Which compiler are you using? Check the vector's capacity - possibly it reserves space for four or more elements up front? – Mike Seymour Jan 07 '14 at 09:29
  • Which compiler is this? Works in gcc (4.7.2 and 4.8.2 - only ones I have access to right now...) – Nim Jan 07 '14 at 09:32
  • @MikeSeymour 4.73 and I've updated the thread, adding capacity printing. – Yue Wang Jan 07 '14 at 09:41
  • @Nim 4.73 and I've updated the thread, adding capacity printing. – Yue Wang Jan 07 '14 at 09:44
  • Sorry, the example snippet I was using I had the destructor as `noexcept` - which is why it worked on 4.7.2. – Nim Jan 07 '14 at 10:02
  • Clang works fine. It might be because the STL vector you are using wasn't implementing move feature? – user534498 Jan 07 '14 at 10:09
  • @Nim I just tried. It works when the **destructor** has been marked with `noexcept`.4 copyS and 3 moveS. So it's a bug ,isn't it? I guess I should update my compiler.. – Yue Wang Jan 07 '14 at 10:17
  • @Alan.W, yes it is, and I guess whether you can upgrade depends on your situation, but I guess so. – Nim Jan 07 '14 at 10:19
  • @Nim but.. How to deal with this post? don't know what do i do for a duplicate.. – Yue Wang Jan 07 '14 at 10:25
  • 1
    Vote to close it, and the question will be marked as closed, other folks will also vote to close and then question will be closed. Don't delete it though, as the information about this being a gcc bug is not very prominent in the other question either. – Nim Jan 07 '14 at 10:27

1 Answers1

1

I reproduce with gcc 4.7.1 on MinGW...

Adding ~String() noexcept solves the issue...

Jarod42
  • 203,559
  • 14
  • 181
  • 302