Nano Hash - криптовалюты, майнинг, программирование

C++: какие конструкторы вызываются в vector‹int› vn{MyAllocator‹int›(a)}?

У меня есть тривиальный распределитель:

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

А это код клиента (используется только один из A, B, C):

#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, то распределитель создается только один раз, это понятно. Но когда вместо A присутствует B, по-видимому, конструктор копирования Mallocator вызывается в B, но вывод не отражает этого. Почему?

(2) Если присутствует B, какой конструктор std::vector вызывается? В этом справочнике единственный конструктор, принимающий список инициализаторов, не т выглядит так. И если я использую C вместо B, он не скомпилируется, и сообщение об ошибке clang++ не поможет.

Эйдт: Я знаю, что этот распределитель тривиален, но суть этого вопроса не в этом.

Код «alloc.h» взят из здесь, в конце страницы.


Ответы:


1

1) Ваш «конструктор копирования» не один. Настоящий конструктор копирования — это не шаблон. Каждый класс получает неявно объявленный конструктор копирования, если он не объявляет его сам. Mallocator<int> не объявляет настоящий конструктор копирования, поэтому он неявно объявляется и определяется для вас. Поскольку ваш класс пуст, этот конструктор копирования ничего не делает и ничего не печатает (и, благодаря правилам разрешения перегрузки, выбирается для копирования распределителя поверх вашего шаблона конструктора).

2) Инициализация списка может вызывать конструкторы без списка инициализаторов, если ни один конструктор списка инициализаторов не является жизнеспособным. B в конечном итоге вызывает тот же конструктор, что и A. Ваш C является случаем самый неприятный анализ.

17.08.2017
  • да, верно, хотя с исправлением этого кода (удаление шаблона из U) он все равно не будет вызывать побочный эффект конструктора копирования. Или, лучше сказать, может быть не позвонит. 17.08.2017
  • @Swift Вы увидите по крайней мере одну копию параметра вектора в хранящийся в нем распределитель. Это невозможно. 17.08.2017
  • это бесспорно. На самом деле, я вижу два, что любопытно (8), разве это не правильный конструктор, который можно вызвать в этом случае. 17.08.2017
  • @Swift (Это потому, что я все равно получу уведомление, и нет никакой двусмысленности в отношении того, кому вы можете отвечать.) Другой из части Mallocator<int>(a). 17.08.2017
  • Да, я только что понял, что... это был долгий день. 17.08.2017
  • Если я действительно хочу иметь определяемый пользователем конструктор копирования, как мне его написать? Я не требую, чтобы аргумент шаблона объекта, скопированного из, был таким же, как аргумент, скопированный в один, - по этой причине конструктор является методом шаблона. 17.08.2017
  • (Продолжение) И, основываясь на вашем ответе о том, что конструкторы не являются шаблонами, правильно ли сказать, что источник кода (ссылка, приведенная в конце моего вопроса) не достигает того, что он намеревался? 17.08.2017
  • @user8385554 user8385554 Конструктор копирования — Mallocator(const Mallocator&) = default;. Стандарт требует наличия как шаблона конструктора преобразования, так и обычного конструктора копирования. Пример cppreference не включает явное объявление конструктора копирования, потому что неявно объявленный конструктор отлично справляется со своей задачей. 19.08.2017
  • @Т.С. спасибо за ваш дружелюбный и информативный комментарий, который более полезен, чем снисходительные слова другого парня. Фактически, я обнаружил, что этот распределитель определяет как конструктор копирования, так и шаблон конструктора преобразования, как вы сказали: стековый_аллокатор 19.08.2017
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..