简体   繁体   中英

Why doenst STL vector call default constructor on allocation?

I got the follwing block of code:

#include <vector>
#include <iostream>

struct TestStruct {
    bool wasCreated;

    TestStruct() {
        std::cout << "Default Constructor" << std::endl;
        wasCreated = false;
    }

    ~TestStruct() {
        if (wasCreated) {
            DoImportantStuff();
        }
    }

    void Create() {
        wasCreated = true;
    }

    // delete all copy stuff
    TestStruct(const TestStruct&) = delete;
    TestStruct& operator=(const TestStruct&) = delete;


    // implement only move assignment & ctor
    TestStruct(TestStruct&& other) {
        std::swap(wasCreated, other.wasCreated);
    }

    TestStruct& operator=(TestStruct&& other) {
        std::swap(wasCreated, other.wasCreated);
        return *this;
    }

    // very important stuff
    void DoImportantStuff() {
        std::cout << "Do Important Stuff" << std::endl;
    }
};

int main() {

    std::vector<TestStruct> testVector;

    testVector.emplace_back(TestStruct());
    testVector.emplace_back(TestStruct());

    std::cin.get();
}

This code leads to the output:

Default Constructor

Do Important Stuff

Default Constructor

Do Important Stuff

Do Important Stuff

Basicly I wanted to write a class, which owns memory but allocates this memory only when I call Create() . To avoid memory leaks and to avoid deleting not allocated memory I introduced wasCreated which will be only true when i call Create() . Every TestStruct should be saved in one vector. So in implemented move assigment & ctor and deleted both copy assigment & ctor.

Now it seems to me that the vector doenst call interally the default constructor of my TestStruct when its allocates new memory. Why is so and how do get the vector to call the default constructor on memory allocation? Do I need my own allocator?

Your problem is that your move constructor is implemented incorrectly. It swaps wasCreated between the newly created object and the one being moved from, but the variable in the newly created object has not been initialized yet (a default-constructed bool has an unknown value). So your temporary objects created with TestStruct() receive an uninitialized bool, which happens to be true in your case, hence the calls to DoImportantStuff() in their destructors.

So the move constructor should look something like this:

// implement only move assignment & ctor
TestStruct(TestStruct&& other) : wasCreated(other.wasCreated) {
    other.wasCreated = false;
}

(You have moved ownership to the newly created object, the old one doesn't own anything anymore.)

Don't confuse the assignment operator with the constructor; they do different things. The assignment operator deals with two objects that are both already constructed ; in the case of the constructor, the object being constructed is, well..., not constructed yet, so it doesn't have a valid state.

By the way, emplace_back() is pointless the way you're using it. Its purpose is to forward its arguments directly to the constructor of the object inside the vector. Since you have a default constructor (no arguments), the call should be:

testVector.emplace_back();

This will default-construct the TestStruct in place.

Now it seems to me that the vector doenst call interally the default constructor of my TestStruct when its allocates new memory.

A default-constructed vector has zero size, so there are no objects to construct.

If you want the vector to default-construct some objects, resize it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM