2010-07-29 3 views
11

В настоящее время я работаю над проектом на C++, который должен иметь как можно меньше внешних зависимостей, и поэтому я в значительной степени придерживаюсь STL и Boost. До сих пор я почти исключительно жил в Qt-land, когда речь зашла о C++. В общем, я стараюсь использовать C# и Python, когда могу.Является ли обтекание идиом STL для удобства чтения хорошей идеей?

Сегодня я хотел проверить, содержит ли std::vector определенный элемент. С Qt я бы сделал это следующим образом:

QList<int> list; 
list.append(1); 
list.append(2); 
list.append(3); 

if (list.contains(2)) 
{ 
    // do something 
} 

Nice и удобочитаемый. Но у std::vector нет никакого метода contains, что было неожиданностью. Хорошо ... что будет для STL-идиомы для чего-то подобного? Поиск вокруг, это выглядит следующим образом:

std::vector<int> list; 
list.push_back(1); 
list.push_back(2); 
list.push_back(3); 

std::vector<int>::const_iterator result = 
    std::find(list.begin(), list.end(), 2); 

if (result != list.end()) 
{ 
    // do something 
} 

Это (для меня) трудно читаемо и слишком много подробностей. Поэтому я обнаружил, что пишу функцию полезности, которая принимает вектор и значение и возвращает bool в зависимости от того, было ли это значение найдено или нет. В принципе, шаблонный метод ; обертка для вышеуказанного вызова std::find. Затем я могу использовать это способом, похожим на пример Qt.

У меня есть несколько подобных функций утилиты, которые могли бы обернуть другие идиомы STL ни по какой другой причине, а (воспринимаемое) увеличение читаемости. То, что я хочу знать, это ... это плохая идея? Другие люди делают то же самое? Я пропустил что-то важное? Код будет OSS в какой-то момент, и я бы предпочел не делать что-то своеобразное, что другие разработчики C++ бывали странными.

+1

@rgrig Это для меня все еще не так читаемо, как пример Qt, и, как вы сказали, это не очень эффективно. Он должен быть O (n/2), а не O (n). – Lucas

+0

Я не уверен, о чем вы говорите, поскольку он, очевидно, удален, но O (n/2) - O (n). Однако, по вопросу эффективности, такая оболочка может быть перегружена для наборов/карт, чтобы использовать их для сортировки без каких-либо изменений на сайте вызова. –

ответ

6

Нет ничего плохого в написании функций утилиты, которые помогут вам и сделают ваш код более чистым. Другие люди делают то же самое. Boost library - это самый большой набор таких функций и классов полезности.

Больше сказать C++ Standard явно предлагает расширить стандартную библиотеку (17.3.1.2/1):

Библиотека может быть расширена с помощью программы C++. Каждое предложение, если применимо, описывает требования, которые должны удовлетворять такие расширения. Такие расширения, как правило, один из следующих:

  • аргументы шаблона
  • Производные классы
  • контейнеры, итераторы, и/или алгоритмы, которые отвечают в конвенции интерфейса
3

Я бы сказал, это определенно хорошая идея. В C++ STL отсутствует много программистов Python/C#, ожидающих от стандартной библиотеки. Если вы можете сделать свой код более читаемым, взяв этот 2-3-строчный подход STL и сделав его одной функцией, продолжайте!

Вот еще один пример очень похожей проблемы: я часто хочу конвертировать int в std::string. К моему большому удивлению, это не так, как это сделать, используя STL. Итак, я написал функцию toStr, которая запускает 2-3 строки, необходимые для посылки int в stringstream и возвращает результат string.

Редактировать: Чтобы уточнить, я рекомендую искать решения boost, прежде чем создавать свои собственные.Мой пример был предназначен для демонстрации ограничений STL, но имеет альтернативную интерпретацию «независимо от того, что STL отсутствует, boost».

+5

boost имеет lexical_cast <>(), который преобразует любые потоки в строку. –

+2

boost :: lexical_cast (str) также выполнит обратное и проанализирует строку и вернет int. – bradgonesurfing

+0

Действительно, это то, что я сейчас использую. Я просто привел пример. :) –

9

boost делает его намного опрятным. Я больше никогда не использую алгоритмы, основанные на итераторе STL . Диапазоны основанные алгоритмы - намного более аккуратная абстракция и приводят к значительно более чистым кодам.

#include <boost/range/algorithm/find.hpp> 

void foo(){ 
    std::vector<int> list; 
    ... 
    ... 
    boost::find(list, 2) != list.end() 
} 
1

достаточно Похоже, в моем текущем проекте, у нас есть файл с именем: stlutils.h, который содержит некоторые методы, такие как содержит(). Реализован как:

template<class Container, class T> 
bool contains(const Container& c, const T& value) { 
    return std::find(c.begin(), c.end(), value) != c.end(); 
} 

Есть больше функций, но я думаю, вы получите точку

1

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

Если vector имеет член , то, безусловно, будет O (n), так как вектор является простым непрерывным списком. Так как это также удобно, это может побудить программистов использовать его регулярно, даже на больших наборах данных, поощряя разработку приложений с плохими алгоритмическими характеристиками. В случае , если важно посмотреть, если контейнер содержит определенный элемент, с добавленной гарантией, что все элементы уникальны, std::set - почти наверняка лучший выбор, с поиском эффективности O (log n) или даже O (1) для std::unordered_set.

Итак, мой личный взгляд: узнайте все контейнеры и функции, предлагаемые STL, и вы найдете в то время как он краток, он поощряет более эффективный стиль программирования. Вы спрашиваете в вопросе, если вам что-то не хватает, и я бы сказал «да» - вы хотите более внимательно подумать о контейнере, который используете. Я использую set вместо vector регулярно в эти дни.

1

Я не большой поклонник оберток, но если они помогут вам, пойдите для этого. Я думаю, вы со временем найдете, что захотите использовать свою служебную функцию с другими контейнерами, кроме std :: vector. В конце концов ваша функция полезности становится настолько общей, что вы можете также использовать std :: find напрямую.

Но вы уверены, что используете подходящий контейнер? std :: set имеет метод count(), который по сути эквивалентен contains(). И это O (log (n)), а не O (n).

Смежные вопросы