【问题标题】:C++: which constructors are called in vector<int> vn{MyAllocator<int>(a)}?C++:在 vector<int> vn{MyAllocator<int>(a)} 中调用了哪些构造函数?
【发布时间】:2018-01-26 06:17:10
【问题描述】:

我有一个简单的分配器:

// 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; }

这是客户端代码(仅使用ABC 之一):

#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;
}

无论使用A还是B,输出始终是这样的:

default ctor is called
---instantiate---
---push_back(1)---
// omitted for brevity..

我的问题

(1) 如果存在A,则分配器只构造一次,这是可以理解的。但是当存在B 而不是A 时,显然Mallocator 的复制构造函数在B 中被调用,但输出并未反映这一点。为什么?

(2) 如果存在B,则调用std::vector 的哪个构造函数?在这个reference 中,唯一采用初始化列表的构造函数看起来不像这样。如果我使用C而不是B,它将无法编译,并且clang++的错误消息没有帮助..

Eidt:我知道这个分配器是微不足道的,但这不是这个问题的重点..

“alloc.h”的代码改编自here,在页面末尾。

【问题讨论】:

    标签: c++ c++11 stl constructor-overloading


    【解决方案1】:

    1) 您的“复制构造函数”不是一个。真正的复制构造函数不是模板。如果每个类本身没有声明一个复制构造函数,则它会隐式声明一个复制构造函数。 Mallocator&lt;int&gt; 没有声明一个真正的复制构造函数,因此会为您隐式声明和定义。由于您的类是空的,因此该复制构造函数什么也不做,也不打印任何内容(并且,由于重载解析规则,选择将分配器复制到您的构造函数模板上)。

    2) 如果没有初始化列表构造函数可行,列表初始化可以调用非初始化列表构造函数。 B 最终调用了与 A 相同的构造函数。您的C 的一个案例。

    【讨论】:

    • 是的,没错,尽管修复了该代码(从 U 中删除模板),它仍然不会调用复制构造函数的副作用。或者,更好的说法是,也许不会调用。
    • @Swift 您将看到从向量参数到它存储的分配器的至少一份副本。这不是可以消除的。
    • 这是毫无疑问的。实际上,我看到了两个,这很好奇(8)在这种情况下可以调用的不是正确的构造函数。
    • @Swift (那是因为无论如何我都会收到通知,而且你可以回复谁也没有歧义。)另一个来自Mallocator&lt;int&gt;(a) 部分。
    • @user8385554 复制构造函数是Mallocator(const Mallocator&amp;) = default;。该标准需要转换构造函数模板和普通的复制构造函数。 cppreference 示例省略了显式复制构造函数声明,因为隐式声明的声明可以正常工作。
    猜你喜欢
    • 2015-12-24
    • 2020-07-15
    • 2018-05-30
    • 2020-12-27
    • 2012-08-01
    • 1970-01-01
    • 2020-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多