Есть ли в C++ аналог функций emplace/emplace_back в C++ 11?

Начиная с C++11, можно написать что-то вроде

#include <vector>
#include <string>

struct S
{

    S(int x, const std::string& s)
        : x(x)
        , s(s)
    {
    }

    int x;
    std::string s;

};

// ...

std::vector<S> v;

// add new object to the vector v
// only parameters of added object's constructor are passed to the function
v.emplace_back(1, "t");

Есть ли C# аналог функций C++, таких как emplace или же emplace_back для контейнерных классов (System.Collections.Generic.List)?

Обновление: в C# подобный код может быть написан как list.EmplaceBack(1, "t"); вместо list.Add(new S(1, "t"));, Было бы неплохо не запомнить имя класса и написать new ClassName в таких ситуациях каждый раз.

4 ответа

Решение

Вы можете немного улучшить вариант @Boo с расширением.
Вы можете создать экземпляр объекта с помощью Activator.CreateInstance, чтобы сделать решение более общим.

public static class ListExtension
{
    public static void Emplace<S>(this IList<S> list, params object[] parameters)
    {
        list.Add((S)Activator.CreateInstance(typeof(S), parameters));
    }
}

Примечание: не проверены параметры типа и количества, поэтому, если вы что-то делаете неправильно, вы получаете ошибки только во время выполнения

В общем, в C# нет ничего похожего, и его потребность намного меньше, чем в C++.

В C#, когда у вас есть List<SomeReferenceType> что у вас есть List<ReferenceToSomeType>Итак, список ссылок с размером каждого элемента 4 или 8 байт (см. Насколько велика ссылка на объект в.NET?). Копирование ссылки не приводит к дублированию базового объекта, поэтому это очень быстро (вы копируете около 4 или 8 байт, и процессор оптимизирован для этой операции, потому что это размер собственного указателя процессора). Итак, когда вы someList.Add(someReference) что вы делаете, это добавление ссылки на ваш List<>,

В C++, когда у вас есть std::vector<SomeType> что у вас есть вектор SomeTypeс размером каждого элемента, равным sizeof(SomeType), Вставка нового элемента в std::vector<> приведет к дублированию вставляемого элемента (клонированный, скопированный... выберите понравившийся глагол). Это дорогая операция.

Довольно часто используемый вами шаблон заключается в том, что вы создаете объект, просто чтобы вставить его в std::vector<>, Чтобы оптимизировать эту операцию в C++11, они добавили два способа сделать это: std::vector<>::emplace метод и поддержка со стороны std::vector<> ход семантический. Разница в том, что семантика перемещения должна поддерживаться SomeType тип (вам нужен конструктор перемещения с noexcept спецификатор), в то время как каждый тип поддерживает emplace (что в итоге просто использовал конструктор размещения).

В C# вы можете использовать метод расширения, чтобы достичь того, что вы хотите

public static class ListExtension
{
    public static void Emplace(this IList<S> list, int x, string s)
    {
        list.Add(new S(x, s));
    }
}

затем используйте это так

myList.Emplace(1,"t");

Кажется, у вас есть следующие проблемы:

  1. Это больше, чтобы набрать по "new S", Но "add" короче чем "emplace", Тип добавляется для вас intellisense (просто нажмите Enter после ввода "new "):


  1. Вы боитесь писать неправильный тип. Ну, вы не можете с List<T>, Intellisense поможет вам печатать, а компилятор не допустит добавления неправильного типа во время компиляции.

  2. Производительность: см. Ответ @Xanatos.

list.Add(new S(1, "t")); идеально подходит для использования.

Вывод: нам не нужно emplace в C#,

Другие вопросы по тегам