Написание установщиков C ++ - PullRequest
0 голосов
/ 30 мая 2018

После прочтения Effective Modern C ++ я пытаюсь найти лучший способ передачи аргументов для сеттеров в классах C ++;представьте следующий сценарий:

Вы пишете приложение, которое анализирует входной файл (например, в формате CVS), передает его в класс модели и затем передает список экземпляров в драйвер базы данных для массовой вставки.

Мыможет говорить только о самой последней и самой лучшей C ++ 14;Я написал свою попытку представить это одним столбцом:

class Person {
    std::wstring _name;
public:
    template<typename T>
    inline void setName(T&& name) { _name = std::forward<T>(name); }
};

Я также написал следующий фрагмент для проверки производительности:

const auto start = std::chrono::system_clock::now();
std::vector<std::shared_ptr<Person>> vec;
for (auto i = 0; i < 999999; i++)
{
    auto p = std::make_shared<Person>();
    p->setName(L"John Chester Doe");

    vec.emplace_back(p);
}   

const auto end = std::chrono::system_clock::now();
std::cout << "Took " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl;

В моей системе это занимает ~ 175 мс, скомпилированных с MSVC2017 Releasex64 с / O2, отключен SDL, без проверок безопасности (/ sdl- / GS-).Из любопытства я попробовал то же самое в C #:

class Person
{
    public string Name { get; set; }
} 


var sw = System.Diagnostics.Stopwatch.StartNew();
var i = 0;
var vec = new System.Collections.Generic.List<Person>();
for (; i < 999999; i++)
{
    var p = new Person();
    p.Name = "John Chester Doe";
    vec.Add(p);
}
sw.Stop();
System.Console.WriteLine("Took {0}ms", sw.ElapsedMilliseconds);

И это дает 77мс в режиме выпуска!Естественно, мой вопрос в том, что я делаю не так?Почему мой код на C ++ медленнее, чем код на C # для такой же операции?

Я пытался использовать struct в C ++ (без разницы), передавая значение с помощью const ref (медленнее), передавая значение с помощью std :: move (медленнее)).Я также попытался использовать noexcept (без большой разницы) даже std :: string (без большой разницы).

Спасибо!

Редактировать

Спасибо всем за предложения, очень ценю это.Похоже, что лучший способ достичь того, чего я хочу достичь, это что-то вроде:

std::vector<Person> vec;
vec.reserve(999999);
for (auto i = 0; i < 999999; i++)
{
    vec.emplace_back();
    vec.back().setName(L"John Chester Doe");
}

Это 75 мс с предварительным распределением, без vec.reserve это 130 мс.

Ответы [ 2 ]

0 голосов
/ 30 мая 2018

Насколько я понимаю, то, что компилятор C # делает в фоновом режиме, примерно преобразуется в следующий код C ++:

class Person {
    std::wstring _name;
public:
    template<typename T>
    inline void setName(T&& name) { _name = std::forward<T>(name); }
};

А для вставки:

std::vector<Person> vec;
vec.reserve(999999);
for (auto i = 0; i < vec.size(); i++)
{
    vec.emplace_back();
    vec.back().setName(L"John Chester Doe");
}

Еще раз спасибо за ваше время, если есть какие-то другие предложения, как улучшить это, я буду рад это услышать.

0 голосов
/ 30 мая 2018

«Сравнение апельсинов с яблоками» - лучшее описание, которое я могу дать здесь.Ваш код C # получил ближайший эквивалент C ++, например:

#include <iostream>
#include <deque>
#include <chrono>
#include <string>

struct Person {
    std::wstring _name;

    Person() = default;
    Person(Person&& p) = default;
    Person(const Person& p) = default;
    Person(const std::wstring& n) : _name(n) {}
};

int main()
{
    std::deque<Person> vec; 
    const std::wstring n =  L"John Chester Doe";
    const auto start = std::chrono::system_clock::now();
    for (auto i = 0; i < 999999; i++)
    {
        vec.emplace_back(n);
    }   

    const auto end = std::chrono::system_clock::now();
    std::cout << "Took " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl;
}

, что по крайней мере в 3 раза быстрее, чем ваш вариант.Возможно, я мог бы сделать это быстрее, перенеся распределение всей памяти в инициализацию deque, но это изменит цикл на дальний.Да, C # делает то же самое, что и Java.Он пытается перегрузить большую часть предсказуемой работы во время компиляции, например, собирая похожие литералы, проецируя используемую память и выделяя ее более эффективно, и т. Д. В основном потому, что CLR работает по принципам, аналогичным java-машине.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...