Как работает emplace с точки зрения памяти?

119
19 ноября 2020, 09:30

Как работает emplace с точки зрения размещения в памяти ?

Вот определение emplace для std::vector с cppreference.com:

Вставляет новый элемент в контейнере непосредственно перед pos. Элемент построен на месте, т.е. не копировать или перемещать операции. Конструктор элемента вызывается с std::forward(args)...аргументы. Тип элемента должно быть EmplaceConstructible, MoveInsertable and MoveAssignable.

Если новый size() больше, чем capacity(), все итераторы и указатели становятся нерабочими. В противном случае, нерабочими становятся только итераторы и указатели на элементы, идущие после вставленных.

Итераторы и указатели остаются в рабочем состоянии.

Параметры

pos — Итератор, перед которой новый элемент будет построен

args — Аргументы направить в конструкторе элемента Оригинал:

Как я понимаю, vector – это непрерывный буфер(выделенный участок) в памяти, у которого мы можем получить значения size и capacity.

Size – возвращает количество элементов в контейнере, а capacity – общее, зарезервированное место.

Суть вопроса:

если vector – непрерывен по своей сути, то как мы можем создать новый элемент прямо на месте по позиции pos – не разрывая вектор или что еще хуже, не создавая новый vector.size +1 и не копируя все элементы в него+ новый?

Т.е если emplace производится по позиции соответствующей size и если size меньше, чем capacity, то мы просто передадим аргументы в конструктор и создадим элемент. В противном случае,если мы вставляем(создаем) объект в позиции, например соответствующей середине вектора, как я понимаю, возможен следующий вариант:

Все элементы после позиции вставляемого сдвигаем на +1 и вставляем в нужной нам позиции.

Но ведь мы должны сначала сдвинуть элементы вектора, что бы потом на освободившемя месте создать новый, и с элементами соответсвующими типу вектора – все понятно, мы знаем смещение, на которое необходимо сдвинуть объекты, но как быть с объектами производных типов?

Вот небольшой пример, иллюстрирующий, что я имею ввиду:

/ // ConsoleApplication1.cpp : Этот файл содержит функцию "main". Здесь начинается и заканчивается выполнение программы.
//
#include "pch.h"
#include <iostream>
#include <vector>
using namespace std;
class Base
{
public:
    int x, y;
    Base() = default;
    virtual ~Base() = default;
};
class Derived :public Base
{
    float z;
public:
    Derived() = default;
    virtual ~Derived() = default;
};
class Base1
{
public:
    virtual void F1()
    {
    }
};
class Derived1 :public Base1
{
     void F1()  override
    {
    }
};
int main()
{
    vector<Base> v(10);
    v.emplace(v.begin() + 2, Derived{});
    vector<Base>::iterator l = v.begin();
    int a = distance(v.begin(), l + 2);
v1.at(a).x;
v1.at(a).y;
v1.at(a).z;//Невозможно – усечене объекта

    ////
    vector<Base1> v1(10);
    v1.emplace(v1.begin() + 1, Derived1{});
    v1.at(a).F1();//усечения быть не должно, т.к может понадобиться реализация из производного класса
}

Вопрос касается виртуальных методов, как в таком случае будет выделяться память под объект, до его построения, в том смысле, что размер объекта из-за vpt точно известен не будет?

Т.е что будет вот в этой ситуации:

v1.at(a).F1();//усечения быть не должно, т.к может понадобиться реализация из производного класса

Т.е я имею ввиду , что мы не можем определить размер объекта, пока не создадим его, а создать мы его не можем – т.к emplace по-определению делает это на месте, а не где-то в отдельном участке памяти, но создать «на-месте» мы тоже не можем, т.к не знаем смещение для сдвига элементов.

Answer 1

Такой вопрос возник из-за ошибочного предположения, что при вставке в контейнер vector<Base> объекта класса Derived в контейнер на самом деле вставится объект класса Derived. На самом деле вставляться будет объект класса Base, так как вектор является гомогенным контейнером, т.е. может содержать объекты только одного класса.

READ ALSO
settimeout, delay, setinterval

settimeout, delay, setinterval

Столкнулся с проблемойМне необходимо через одинаковые промежутки времени вызвать одну и туже функцию

105
Убрать навигацию на предпросмотре в iframe vimeo

Убрать навигацию на предпросмотре в iframe vimeo

на сайте стоит встроенное видео с плеера vimeo

130