What is the difference betwwen the older alloctaor::construct and the new one and explicit constructor?
Asked Answered
C

1

10

As I know std::allocator<T>::construct takes only two parameters on older version of C++; the first is a pointer to raw, un-constructed memory in which we want to construct an object of type T and the second one is a value of element type to initialize that object. So the copy-constructor is invoked:

struct Foo {
    Foo(int, int) { cout << "Foo(int, int)" << endl; }
    /*explicit*/ Foo(int) { cout << "Foo(int)" << endl; }
    Foo(const Foo&) { cout << "Foo(const Foo&)" << endl; }
};

int main(int argc, char* argv[]) {


    allocator<Foo> a;
    Foo* const p = a.allocate(200, NULL); // second parameter is required on C++98 but on C++11 it is optional
//  Foo* const p = a.allocate(200); // works fine on C++11 but not on C++98

    a.construct(p, 5, 7); // works on C++ 11 and up but not C++98
    a.construct(p, 10);// works on both
    a.destroy(p);
    a.destroy(p + 1);
    a.deallocate(p, 200);



    std::cout << std::endl;
}
  • Why on C++98 a.construct(p, 10) calling the copy constructor but on C++11 and above is calling just the constructor that takes an integer?

  • Does this mean on C++ 11 because of some Copy-elision optimization even if the constructor Foo(int) is explicit works on such call: a.construct(p, 5) works on C++11 even the constructor is explicit what I am sure of is it doesn't works on C++98 if Foo(int) is explicit.

  • If so then if I compile that statement with some sort of disabling copy-elision optimization will cause the compiler fail? Thank you.

Cinthiacintron answered 7/11, 2019 at 12:58 Comment(1)
Short answer: until C++11, there was no perfect fowarding. Details provided below by @flyx. Note that there is no copy elision involved (no pass-by-value or return-by-value).Airdrop
G
13

This is because the declaration of construct changed in C++11:

void construct( pointer p, const_reference val );  (1)  (until C++11)
template< class U, class... Args >
void construct( U* p, Args&&... args );            (2)  (since C++11)

The first declaration calls the copy constructor, while the second declaration calls a constructor that matches the given list of arguments. This could be the copy constructor, but also another constructor as you saw in your code.

a.construct(p, 10) calls the copy constructor in C++98 because the 10 is implicitly converted to Foo via the Foo(int) constructor. This conversion is not necessary in C++11 since there is a matching constructor that takes an int (exactly the constructor that was used for converting in C++98). This is also the reason why the code doesn't work in C++98 when you add explicit – it cannot convert the 10 to a Foo then.

Gipson answered 7/11, 2019 at 13:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.