Вопрос

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......
Это было полезно?

Решение

I reproduce with gcc 4.7.1 on MinGW...

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top