C++: which constructors are called in vector<int> vn{MyAllocator<int>(a)}?

青春壹個敷衍的年華 提交于 2020-01-15 12:16:15

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!