LINUX.ORG.RU

Стиль или как правильно

 ,


0

2

Здравствуйте. Какой способ получения контейнера из класса предпочтительнее для каждого из вариантов списка:

  • по значению;
  • без копирования, с возможностью редактирования полученного контейнера;
  • без копирования и без возможности редактирования.
#ifndef MYCLASS_H
#define MYCLASS_H

#include <vector>

class MyClass
{
public:
    MyClass();
    std::vector<int> getVec0();
    std::vector<int> &getVec1();
    const std::vector<int> &getVec2();
    void getVec3(std::vector<int>::iterator &itBeg, std::vector<int>::iterator &itEnd);
    void getVec4(std::vector<int>::const_iterator &itBeg, std::vector<int>::const_iterator &itEnd);
    void getVec5(std::vector<int> &vec);
    void getVec6(std::vector<int> *vec);

private:
    std::vector<int> myVec;
};

#endif // MYCLASS_H

И ещё вопросик, насколько допустимо объявление структур и функций не являющихся членами класса в *.h, но используемых в реализации функций-членов в *.cpp? Например, есть у меня обёртка для функций boost::spirit, заголовочные файлы и структуры, определяющие грамматики, объявлены только в parser.cpp и никак не фигурируют в parser.h.

/* parser.h */
//...
class MyParser
{
public:
    void getMyCon(string str, vector<int>::const_iterartor &itBegin, vector<int>::const_iterator &itEnd);
private:
    vector<int> myCon;
};
//...
/* parser.cpp */
#include "myparser.h"
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
//...

void foo(vector<int> &vec, int val)
{
    //...
}

template <typename Iterator>
struct MyGrammar
        : qi::grammar<Iterator, vector<int>(), qi::space_type>
{
    //...
};

void MyParser::getMyCon(string str, vector<int>::const_iterartor &itBegin, vector<int>::const_iterator &itEnd)
{
    //...
}


Последнее исправление: v0r0n (всего исправлений: 1)

Например, есть у меня обёртка для функций boost::spirit, заголовочные файлы и структуры, определяющие грамматики, объявлены только в parser.cpp и никак не фигурируют в parser.h.

совершенно нормально. это даже лучше, мусора в .h не будет.

crowbar
()
Ответ на: комментарий от crowbar

А обязательно ли функции, которые есть только в .cpp, оборачивать в анонимное пространство имён?

v0r0n
() автор топика
Ответ на: комментарий от v0r0n

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

quiet_readonly ★★★★
()
Ответ на: комментарий от v0r0n

А обязательно ли функции, которые есть только в .cpp, оборачивать в анонимное пространство имён?

если функция используется и ДОЛЖНА использоваться только в пределах этого cpp, то ИМХО - да.

1. это документация для читателя кода 2. (не уверен, не знаю мат. часть) защита от джедаев с extern наперевес

Stil ★★★★★
()
Ответ на: комментарий от v0r0n

А обязательно ли функции, которые есть только в .cpp, оборачивать в анонимное пространство имён?

Да, это уменьшит кол-во коллизий имен (когда в другом cpp будет такой же метод). Еще можно юзать

static void foo(vector<int> &vec, int val)
с тем же эффектом. И это еще немного ускорит линковку.

Pavval ★★★★★
()
Ответ на: комментарий от quiet_readonly

А если в этих функциях модифицируются данные-члены класса (функции вызываются из грамматик и передают туда ссылку на vector), не вызовет ли это каких либо непредвидиных проблем? P.S.: я не про неймспейсы, а вообще про такой подход.

v0r0n
() автор топика

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

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

Интерфейс (класса, хедера) должен быть как можно более простым и закрытым. Есть такое хорошее правило - «запрещено всё, что не разрешено». Позволяет избегать много проблем.

Почитай что-нибудь по ООП. Принципы SOLID, например.

E ★★★
()
std::vector<int> &getVec1();
    const std::vector<int> &getVec2();

Убивать. Потому что это требует от класса хранить сам вектор у себя внутри и не трогать его. Подумай - ты передаешь ссылку на объект все вызвавшим этот метод. Одну и ту же, или разные? А где должен храниться сам возвращаемый объект? Если внутри MyClass, то что будет, если твой MyClass уничтожат до прекращения использования вектора?

Юзай одно из

 void getVec5(std::vector<int> &vec);
    void getVec6(std::vector<int> *vec);
на выбор. Конкретный вариант является объектом срача.

Pavval ★★★★★
()
Ответ на: комментарий от v0r0n

Оно же, вроде как, deprecated и оставлено лишь только для совместимости?

Никакого deprecated в стандарте нету.

Pavval ★★★★★
()

В общем случае - никакой. Всё исходя из роли класса и его обязанностей.

yoghurt ★★★★★
()

Семантика перемещения тоже может быть очень хороша.

pathfinder ★★★★
()

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

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

Ну ок. А что про функции не члены класса, которые определены в .cpp, и в которых модифицируются данные-члены класса скажете?

v0r0n
() автор топика
Ответ на: комментарий от v0r0n
namespace {

тут твои темплейты, тайпдефы и прочая мишура.

} //namespace

static не устарел. Он используется в С и работает только для ф-ий. Никто не запрещает его и в спп использовать, но зачем если есть неймспейсы.

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

Я про то, что нет ли каких камней подводных при таком подходе и на сколько это вообще правильно?

v0r0n
() автор топика
template<class OutputIterator>
void f(OutputIterator it) {
...
   *it = some_val;
   it++;
...
}

// usage
std::vector<int> v;
f(std::back_inserter(v));
BlackHawk
()
Ответ на: комментарий от Pavval

Убивать. Потому что это требует от класса хранить сам вектор у себя внутри и не трогать его.

Эээээ? Ну если вектор уже есть в классе... Да и с 1 строкой, почему не трогать? :)

Да вообще это не коде стиль.

Можно и констами обвешаться :)

const std::vector<int> &getVec2() const;
                                  ^^^^^

zJes ★★
()
Ответ на: комментарий от v0r0n

В спп всё - правильно ))

Любой метод класса принимает this как параметр неявно. Так что на самом деле метод SomeClass::getVector() есть обычная сишная функция someclass_getVector(SomeClass_s *), где SomeClass_s - это структура [1].

Если ты в .срр файле определил ф-ию, которая в параметрах имеет указатель на объект твоего класса, то технически он ничем от обычного метода не отличается. Но учти, что к виртуальным методам это не применимо.

Честно говоря в голову не приходит случая, когда такой подход что-то там нарушал бы. Разве что работат всяких метакомпиляторов, которые парсят хидер и делают всякие автоматически сгенерированые классы для каких-то целей.

В общем я так иногда делаю, но без фанатизма, всё работает.

[1] http://www.cs.rit.edu/~ats/books/ooc.pdf

nanoolinux ★★★★
()
Ответ на: комментарий от zJes

Эээээ? Ну если вектор уже есть в классе... Да и с 1 строкой, почему не трогать? :)

Если это не тупой геттер (а тогда без const никак), а результат выполнения ф-ции, то это полный песец. Очень классно получить вектор, а потом увидеть, что он внезапно изменился из-за повторного вызова метода далее в коде. Про уничтожение объекта до окончания использования вектора я уже говорил.

Pavval ★★★★★
()
Ответ на: комментарий от nanoolinux

Никто не запрещает его и в спп использовать, но зачем если есть неймспейсы.

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

Pavval ★★★★★
()
Ответ на: комментарий от Pavval

Убивать. Потому что это требует от класса хранить сам вектор у себя внутри и не трогать его.

Обожаю этих нулёвых балаболов.

Ссылка в бомжатских плюсах имеет такую фичу:

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>

typedef std::vector<int> int_vec_t;
template<typename vec_T, typename fun_T> void for_each1(vec_T vec, fun_T fun) {std::for_each(vec.begin(), vec.end(), fun);}
#define for_each1(A, B) for_each1(A, [](typeof(*((A).begin())) it) B)// в вашем недодоязычке даже форич ущербен

typedef struct myclass {
  myclass(int_vec_t vec) : local_vec(vec){};
  int_vec_t & get_vec() {return local_vec; }
  void sort() { std::sort(local_vec.begin(), local_vec.end());}
  int_vec_t local_vec;
} class_t;

int main() {
  class_t t((int_vec_t){3, 2, 1});
  int_vec_t & ref = t.get_vec();//ref type * t = (type *);
  int_vec_t dup = t.get_vec();//copy type t = *(type *);
  t.sort();
  for_each1(ref, {std::cout << it << " ";});std::cout << std::endl;
  for_each1(dup, {std::cout << it << " ";});std::cout << std::endl;
  memset(&t, 0, sizeof(t));
  for_each1(ref, {std::cout << it << " ";});std::cout << std::endl;
  for_each1(dup, {std::cout << it << " ";});std::cout << std::endl;
}

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

на выбор. Конкретный вариант является объектом срача.

Это говно. Если ты хочешь дубликат в куче - это делается так:

int_vec_t * get_dupvec() {return new int_vec_t(local_vec);}//я уж не помню как точно это делается в вашем недоязычке.

Если написать так:

int_vec_t & get_dupvec() {return *(new int_vec_t(local_vec));}

То будет так же - int_vec_t & ret = get_dupvec(); - ret будет реально лежать в куче, которую мы захреначили, а вот: int_vec_t ret = get_dupvec(); - ret будет уже копией на стеке(либо ещё в какой жопе). Это так же даёт проблемы с auto, а так же ваш говнокод тупо месит память. Такая же мура и с аргументами, которые ты передаёшь.

Единственный более-мене вариант с указателем - это:

void get_dupvec(int_vec_t * ret) { new(ret) int_vec_t(local_vec);}
Только тут указатель уже должен на что-то указывать - т.е.:
int_vec_t * vec = (int_vec_t *)malloc(sizeof(class_t));get_dupvec(vec);

Т.е. ты советуешь пацану абсалютную ересь, балаболишь, при этом нихрена не знаешь даже о своём недоязычке.

anonymous
()

по значению;

Какому значению? Локальная копия? Копия в куче? Все ваши глупые вопросы - следствие тотального детсада. Я выше написал что, как и почему.

без копирования, с возможностью редактирования полученного контейнера;

Ссылка на ссылку. type & ref = get(); type & get(void);

без копирования и без возможности редактирования.

Возможность редактирования есть в блоке всегда. const - юзай взависимости от нюансов и того, что нужно. Причем конст это в 95% случаев в плюсах тупо синтаксическая проверка - т.е. нельзя юзать присваивание на указатель/ссыл/«объект», который константен. На это семантика заканчивается.

Только это никак не относится к твоему контейнеру, данным и прочему.

И ещё вопросик, насколько допустимо объявление структур и функций не являющихся членами класса в *.h, но используемых в реализации функций-членов в *.cpp? Например, есть у меня обёртка для функций boost::spirit, заголовочные файлы и структуры, определяющие грамматики, объявлены только в parser.cpp и никак не фигурируют в parser.h.

Открою тебе тайну - чем меньше твой код говно, тем меньше ты юзаешь *.cpp и наоборот.

Твой недоязычек имеет нереальные оверхеды, поэтому писать на нём можтно только в «хеадер-онли» стайле. Так написан stl(не доконца, но более-менее), так написан буст, твой спирит и остальное.

/* parser.cpp */

Так пишут только говно.

Есть кастыли, аля #include «parser.cpp» вконце /* parser.h */, чтобы твоё говно хоть свернулось в более-менее вменяемый код.

Тебе надо определится в понятиях, ибо неясно что ты понимаешь под «лучше» - лучше по мнению кодестайлов для нулей? Лучше == популярней? Либо всётаки лучше - это лучше с точкизрения качества кода? Причем что в твоём понимании качество.

anonymous
()

ООП межушного ганглия?

Здравствуйте. Какой способ получения контейнера из класса предпочтительнее для каждого из вариантов списка:

Вот такой:

#ifndef MYCLASS_H
#define MYCLASS_H

#include <vector>

class MyClass
{
public:
    MyClass();
    std::vector<int> myVec;
};
#endif // MYCLASS_H

//...

и далее:

MyClass mc;
//...

// по значению;
std::vector<int> foo = mc.myVec;

//без копирования, с возможностью редактирования полученного контейнера;
std::vector<int>& foo = mc.myVec;

//без копирования и без возможности редактирования.
const std::vector<int>& foo = mc.myVec;

peacelove
()
Ответ на: комментарий от anonymous

Кто упоротый?

Открою тебе тайну - чем меньше твой код говно, тем меньше ты юзаешь *.cpp и наоборот.

Гражданин, а вы уже сколько часов под веществами?

peacelove
()
Ответ на: ООП межушного ганглия? от peacelove

А вы точно не пропустили аперсанд?

    std::vector<int> &myVec();

Вообще, да, так приятнее всего читать, но не безопасно в случае если необходимо именно «без копирования и без возможности редактирования».

v0r0n
() автор топика
Ответ на: комментарий от v0r0n

Какой амперсанд?

myVec это поле вообще-то //std::vector<int> &myVec(); ??? что за амперсанд?

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

peacelove
()
Ответ на: комментарий от anonymous

Открою тебе тайну - чем меньше твой код говно, тем меньше ты юзаешь *.cpp и наоборот.

Господин Ананимус, забыли рассказать как приятно отлаживать это не говно, которое всё, или почти всё, находится хедерах... Лично у меня начинается батхёрт когда пирходится парсить эту гору строчек в попытках найти ошибку.

v0r0n
() автор топика
Ответ на: Кто упоротый? от peacelove

Кто упоротый?

Твои фантазии.

Гражданин, а вы уже сколько часов под веществами?

О5 нулёвый балабол хочет со мной поспорить. Не беспокойся, авось когда-то ты захочешь написать что-то похожее не на кусок говна - ты возможно поймёшь зачем нужно хеадеронли, а пока не дано.

Хотя давай я тебе дам пищу, хотя ты слепой, ибо я уже примеры для размышления давал. Дак вот - идёшь и смотришь сколько *.cpp в бусте и stl. Потом учишь матчасть и пытаешься понять зачем это и почему. Возможно ты что-то в этой жизни осилишь понять, кроме жалкого балабольства.

anonymous
()
Ответ на: Какой амперсанд? от peacelove

А ну да, не доглядел... Тогда как правильнее вернуть «без копирования и без возможности редактирования»?

v0r0n
() автор топика
Ответ на: комментарий от v0r0n

Господин Ананимус, забыли рассказать как приятно отлаживать это не говно

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

которое всё, или почти всё, находится хедерах

Что там отлаживать? У вас в классе есть контекст - вы можете просто функции(с минимумов аргументов и возвратов) по 2строчки писать и из них составлять - пишите. Если же вы пишите говно - это ваши проблемы.

Посмотри сколько строчек занимает мой код, а сколько твоя говнолапша.

Лично у меня начинается батхёрт когда пирходится парсить эту гору строчек в попытках найти ошибку.

Гора строчек - это твоё говно. У тебя только на твоём ущербанском скобкастайле теряется 50-60% места.

Для справки:

typedef struct myclass {
  myclass(int_vec_t vec) : local_vec(vec) {};
  int_vec_t & get_vec() { return local_vec;}
  void sort() { std::sort(local_vec.begin(), local_vec.end());}
  int_vec_t local_vec;
} class_t;
//.h
typedef struct myclass 
{
  myclass(int_vec_t vec);
  int_vec_t & get_vec();
  void sort();
  int_vec_t local_vec;
} class_t;
//.cpp
тут ещё тысяча инклюдов, либо кастылей.

myclass::myclass(int_vec_t vec) : local_vec(vec)//оверхед раз
{//оверхед 2
}
int_vec_t& myclass::get_vec()
{
  return local_vec;
}
void myclass::sort()
{
  std::sort(local_vec.begin(), local_vec.end());
}

Инфа сотка, что второй вариант «не гора строчек». У тебя оверхед 2строчки на функцию минимум.

Т.е. если в среднем будет 50методов по 5строк - это 300строк в моём исполнении в .h и 350 у тебя в cpp и 50+ в .h

А если с учетом того, что я пишу более по-пацаночке, то у меня будет в среднем не 5строк, а максимум 4, если не 3.

В конечном итогде твоё балабольство и придирки - следствией твоей анскильности, веры в мифы и легенды соседей по цеху/парте. Объективно ты сливаешь по всем фронтам.

Ты не можешь разобраться даже в собственном коде? Какие-такие ошибки ты ищешь - расскажи хоть мне, ибо я себе представить это не могу.

anonymous
()
Ответ на: комментарий от false

Я и не уходил. Чет ты какой-то знакомый нулевичек - я с тобой болтал? Ты мне хоть посуществу ответь что-нибудь, а то тут вообще пичаль и анскилл.

anonymous
()

Какой способ получения контейнера из класса предпочтительнее для каждого из вариантов списка

по возможности нужно передавать меньше информации.

И ещё вопросик, насколько допустимо объявление структур и функций не являющихся членами класса в *.h, но используемых в реализации функций-членов в *.cpp? Например, есть у меня обёртка для функций boost::spirit, заголовочные файлы и структуры, определяющие грамматики, объявлены только в parser.cpp и никак не фигурируют в parser.h.

вот и правильно НЕ фигурируют. Значит ты их можешь поменять, не ломая остальной код. Также и баги проще искать, зная, что в эти структуры никто кроме твоего парсера не лезет (ибо не может).

emulek
()
Ответ на: комментарий от v0r0n

А обязательно ли функции, которые есть только в .cpp, оборачивать в анонимное пространство имён?

это хорошая практика.

emulek
()
Ответ на: комментарий от zJes

Можно и констами обвешаться

не «можно», а НУЖНО. А то ведь хрен догадаешься, что это твоё getVec2() ВНЕЗАПНО меняет поля класса!

emulek
()
Ответ на: комментарий от anonymous

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

мудилко, operator=() можно и НУЖНО перезагружать. Даже если он не нужен, его надо делать private, как раз для защиты от таких мудаков как ты.

emulek
()
Ответ на: комментарий от anonymous

Я и не уходил.

и это печально...

Ты мне хоть посуществу ответь

попробуй водку и анашу. И слезай с того, чем ты сейчас упоролся.

emulek
()
Ответ на: комментарий от emulek

мудилко, operator=() можно и НУЖНО перезагружать. Даже если он не нужен, его надо делать private, как раз для защиты от таких мудаков как ты.

Что конкретно хотел сказать, питух? К чему ты это вообще балаболишь? Мне тебя обоссать ещё раз? Ты обосрался везде и теперь пукан полыхает? И как всегда несёшь херню лижбы нести? Это пичально.

Ещё раз повторю, нулина обоссанная, причем тут твой оператор?

anonymous
()
Ответ на: комментарий от anonymous

Что конкретно хотел сказать

то, детка, что дубликаты в C++ делаются так:

x = y;
а создаются дубликаты так:
Type x = y;
а ты написал какое-то говно.

emulek
()
Ответ на: комментарий от emulek

то, детка, что дубликаты в C++ делаются так:

Чего дубликаты, ушмарок. Какие С++? Что делаются? Т.е. ты как всегда обосрался.

x = y;

Что это? Причем тут твоё x, причем тут твоё y? Ты это к чему?

а создаются дубликаты так:

Что? Кто создаётся, какие дубликаты?

а ты написал какое-то говно.

Обоссанная макака - ты по существу что-то будешь кукарекать, либо будешь обсираться как всегда?

Идёшь ушмарище и конкретно разбираешь и описываешь чем говно, почему говно. Херню нести ты будешь своим соседям-ушлёпкам по парте. Скорее всего ты обосраёшься и заткнёшься, хотя ты уже обосрался и заткнулся, но всё же - ламерок, ты реально не понимаешь, что твоё место рядом с парашей? Тебя уже макнули в говно 100раз, ты обсираешься под себя и воняешь мне тут - вот знай своё место, питух.

Думаешь я тут тебе буду терперть херню, которую ты высрал своим недопародиейнамозг?

anonymous
()
Ответ на: комментарий от anonymous

Чего дубликаты

объекта C++, придурок.

Что это?

operator=(), придурок.

Кто создаётся

объект C++, придурок.

ты по существу что-то будешь кукарекать

нет придурок. Кукарекать — твоя привилегия.

emulek
()
Ответ на: комментарий от emulek

И о5 обосрался.

объекта C++, придурок.

Какого нахрен объекта, какого нахрен С++? Ущербная питушня.

operator=(), придурок.

Причем тут оператор, ущербан.

объект C++, придурок.

Какой нахрен объкт, какой нахрен С++?

нет придурок. Кукарекать — твоя привилегия.

То-то ты обосрался в каждой теме.

Ты ссань будешь что-то вменяемое балаболить, либо продолжишь нести херню, лижбы не призновать тот факт, что ты обосрался?

Я даже тебе помогу: Отвечай на вопросы, говно. Вгоняем в говно, эту обоссанную тупую рожу.

int_vec_t & get_vec() {return local_vec; }

Причем тут оператор прошмандовка. Нука попацаночке объясни что мне надо сделать, как мне сюда надо прибить «Объект С++», «operator=()», чтобы не получишь говнокод и не быть идиотом в твоём ущербанском «понимании».

Нука нука, давай примерчик выкати - обосрись и заткнись.

anonymous
()
Ответ на: комментарий от anonymous

И о5 обосрался.

подмойся.

Какого нахрен объекта, какого нахрен С++? Ущербная питушня.

тебе не понять.

int_vec_t & get_vec() {return local_vec; } Причем тут оператор прошмандовка. Нука попацаночке объясни что мне надо сделать, как мне сюда надо прибить «Объект С++», «operator=()», чтобы не получишь говнокод и не быть идиотом в твоём ущербанском «понимании».

для начала весь код целиком привести, и сказать, чего ты хочешь, придурок.

emulek
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.