问题
I have a trivial allocator:
// alloc.h
#include <cstdlib>
#include <new>
#include <iostream>
template <class T>
struct Mallocator {
typedef T value_type;
Mallocator() {
std::cout << "default ctor is called" << std::endl;
}
template <class U> Mallocator(const Mallocator<U>&) {
std::cout << "copy ctor is called" << std::endl;
}
T* allocate(std::size_t n) {
std::cout << "Mallocator::allocate(size_t n) is called, n = " << n << " ";
if(n > std::size_t(-1) / sizeof(T)) throw std::bad_alloc();
if(T *p = static_cast<T*>(std::malloc(n*sizeof(T)))) {
std::cout << "return p = " << std::hex << (uintptr_t)p << std::dec << std::endl;
return p;
}
throw std::bad_alloc();
}
void deallocate(T* p, std::size_t n) {
std::cout << "Mallocator::deallocate(T *p, size_t n) is called, p = " << std::hex << (uintptr_t)p << std::dec << " n = " << n << std::endl;
std::free(p);
}
};
template <class T, class U>
bool operator==(const Mallocator<T>&, const Mallocator<U>&) { return true; }
template <class T, class U>
bool operator!=(const Mallocator<T>&, const Mallocator<U>&) { return false; }
And this is the client code (only one of A
, B
, C
is used):
#include "alloc.h"
#include <vector>
#include <iostream>
using namespace std;
int main() {
Mallocator<int> a;
cout << "---instantiate---" << endl;
// vector<int, Mallocator<int>> v(a); // A
vector<int, Mallocator<int>> v{Mallocator<int>(a)}; // B
// vector<int, Mallocator<int>> v(Mallocator<int>(a)); // C
cout << "---push_back(1)---" << endl;
v.push_back(1);
cout << "---push_back(2)---" << endl;
v.push_back(2);
cout << "---push_back(3)---" << endl;
v.push_back(3);
cout << "---push_back(4)---" << endl;
v.push_back(4);
cout << "---push_back(5)---" << endl;
v.push_back(5);
cout << "---exiting---" << endl;
}
The output, no matter A
or B
is used, is always this:
default ctor is called
---instantiate---
---push_back(1)---
// omitted for brevity..
My question:
(1) if A
is present, the allocator is just constructed once, that's understandable. But when B
is present instead of A
, apparently the copy constructor of Mallocator
is called in B
, but the output doesn't reflect this. Why?
(2) If B
is present, which constructor of std::vector
is called? In this reference, the only constructor that takes an initializer list doesn't look like this. And if I use C
instead of B
, it won't compile, and the error message of clang++ is not helping..
Eidt: I know this allocator is trivial but it is not the point of this question..
The code of "alloc.h" is adapted from here, at the end of the page.
回答1:
1) Your "copy constructor" isn't one. A real copy constructor isn't a template. Every class gets a copy constructor implicitly declared if it doesn't declare one itself. Mallocator<int>
doesn't declare a real copy constructor, so one gets implicitly declared and defined for you. Since your class is empty, that copy constructor does nothing and prints nothing (and, thanks to the overload resolution rules, is selected to copy the allocator over your constructor template).
2) List-initialization can call non-initializer-list constructors if no initializer-list constructor is viable. B
ends up calling the same constructor as A
. Your C
is a case of the most-vexing-parse.
来源:https://stackoverflow.com/questions/45741769/c-which-constructors-are-called-in-vectorint-vnmyallocatorinta