LINUX.ORG.RU

C чего начать изучение С++?


0

2

Решил попробовать поучить С++, хороший учебник есть. Возникла идея попрактиковать.

Думаю написать графический интерфейс для одной консольной проги. Стоит ли начинать с этого?

Ответ на: комментарий от son_of_a_gun

тред не уничтожается по завершению main

Вот это новости!

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

Ты не привёл кода Runnable, поэтому обсуждать «правильность» довольно бессмысленно. Тем не менее, некоторые плюшки сразу «режут глаз».

1. delete this — антипаттерн. Если и применять delete this, то надо запретить инстацию объекта иначе, чем через new (перекрыть new и сделать конструктор приватным). Возможно, твой Runnable имеет протектед конструктор, а finally() вызывается из деструктора — тогда совсем глупо, деструктор никогда не будет вызван...

2. Создание объекта с неинициализированными полями  — моветон.

3. Код не exception safe: new может выкинуть exception, и оно всё встанет на уши.

Вообще же, на Це этот алгоритм был бы проще, читабельнее и короче (если, как сделано у тебя, скрыть обёртку threads в отдельном модуле).

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

Напиши.

А как насчёт «ненужностей»? Ну ладно: хотя бы парочку назови.

PS: А по поводу неодинаковости С и С++ поищи у Страуструпа. Он именно про это где-то (точно не помню) писал.

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

bit flags даже в стандартных потоках есть. И да какая связь между идиотизим программиста и ЯП?

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

Вообще же, на Це этот алгоритм был бы проще, читабельнее и короче

а как насчет аналога такого простого кода:

{
    map<string,string> cache;
    cache[ "123" ] += "abc";
}

?

vaino
()
Ответ на: комментарий от vaino
#include <string.h>
#include <glib.h>

int main (int argc, char *argv[])
{
    GHashTable *cache = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
    g_hash_table_insert (cache, "123", strdup ("abc"));
    strcat (g_hash_table_lookup (cache, "123"), "d");
    g_hash_table_destroy (cache);
    return 0;
}

Проблемс?

anonymous
()
Ответ на: комментарий от son_of_a_gun
#include "thread.h"

void run(int &i, int &max) {
    for(; *i <= *max; *i++) {
        sleep(1);
        printf("%d:::\n", *i);
    }
}

int main() {
    static int i, max;
    i = 0;
    max = 5;
    thread_start(run, &i, &max);
    printf("end\n");
    return 0;
}

Вывод:

end
5:::
6:::
7:::
8:::
9:::
10:::

*trollface*

ei-grad ★★★★★
()
Ответ на: комментарий от vaino

ам найдешь ошибки и разницу в алгоритме?

какие ошибки? Чувачок, я писал этот код по тому первому варианту, который ты невозбранно удалил

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

ух, кто-то эту хуйню ещё скомпилить попытался?.. ну ладно, на, компиль

#include "stdio.h"

void run(int *i, int *max) {
    for(; *i <= *max; *i++) {
        sleep(1);
        printf("%d:::\n", *i);
    }
}

int main() {
    static int i, max;
    i = 0;
    max = 5;
    thread_start(run, &i, &max);
    printf("end\n");
    return 0;
}
ei-grad ★★★★★
()
Ответ на: комментарий от DeVliegendeHollander

Тоже неплохая идея. Но для начинающего тяжеловата. Может не потянуть.

http://www.planetpdf.com/codecuts/pdfs/ooc.pdf

С помощью книги по ссылке выше, это не так сложно. Нужно внимательно читать и делать все что там написано. Книга очень легко читается, есть примеры.

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

Спасибо, не знал про такую. Даже себе качнул из любопытства. Да и учиться никогда не поздно, даже мне. :)

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

какие ошибки?

1) strdup кроме того, что нестандартная функция( ну и ладно ), но strcat к ее результату применять - чистое ССЗБ, поставь строку подлиннее «d» в качестве аргумента - и 99.99% получишь креш
2) ключ ес-но не статичная строка, нет в этом смысла - ты просто сэкономил на коде
3) нет проверки на наличие элемента, lookup вернет NULL - получишь опять креш, хотя надо добавить новый элемент, я специально переправил пример, чтоб показать, что это сделается автоматом, хотя согласен - как для задачи это было не очевидно

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

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

1) strdup кроме того, что нестандартная функция( ну и ладно ),

Стандартная

но strcat к ее результату применять - чистое ССЗБ, поставь строку подлиннее «d» в качестве аргумента - и 99.99% получишь креш

Вот этот момент я действительно упустил - отвык-c. Но суть ясна, а переписывать пример на GString мне лень

2) ключ ес-но не статичная строка, нет в этом смысла - ты просто сэкономил на коде

Что? Такой же строковый литерал, как и у тебя

) нет проверки на наличие элемента, lookup вернет NULL - получишь опять креш,

Не вернет, не получу. Я ведь только что добавил такой ключ :P

хотя надо добавить новый элемент

Ты на функцию-то посмотри. Семантика lookup не предусматривает добавление элемента при его отсутствии, это ж, мать его, всего лишь лукап!

А вот с поведением std::map<T>::operator[] в этом плане я капитально не согласен - создание пустого элемента при обращениии к несуществующему ключу я нахожу 1) ошибочным 2) влекущим за собой кучи ошибок от нубов. Я уже не один такой косяк исправил на код-ревью своих младших товарищей. Поэтому только явные find, insert, erase! Для доступа по ссылке к значению по _имеющемуся_ ключу можно, конечно, оставить и [], но с добавлением через него я не согласен в принципе.

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

Так уж и быть

#include <glib.h>

void g_string_myfree (void *str)
{
    g_assert (str != NULL);
    g_string_free ((GString *) str, TRUE);
}

int main (int argc, char *argv[])
{
    GHashTable *cache = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_string_myfree);
    g_hash_table_insert (cache, "123", g_string_new ("abc"));
    g_string_append (g_hash_table_lookup (cache, "123"), "d");
    g_hash_table_destroy (cache);
    return 0;
}

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

Вообще всё это - игрушечные примерчики.

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

Но для начинающего тяжеловата.

Ну да-да. :) Нето, конечно, написал, не перед началом изучения ООПнутого языка, а наверное даже потом, для лучшего понимания как оно работает.

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

Там довольно куцая объектная система. CERN-овский COS куда интереснее, например (проекция объектной системы, описанной в AMOP и используемой в CL, на Си)

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

Что? Такой же строковый литерал, как и у тебя

нет, если б я написал «map<const char*» - то было бы как меня, итого ты опять сэкономил

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

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

vaino
()

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

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

Пока и куцая сойдёт на посмотреть. :) Я просто не интересовался подобными проектами, а сейчас любопытно стало. Если можно, ссылку подкинь. Если нет, ладно, будет время - сам погуглю.

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

Гыгылол. В приведенной мною реализации в качестве ключей может быть любой строковый буфер, если ты до сих пор не усёк. Хоть с диска считанный, хоть юзером введенный.

Единственное что, надо будет аргументик NULL в вызове g_hash_table_new_full заменить на g_free, дабы подчищать и память ключей при дестрое хэша.

Дальше то что?

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

Гран, гран мерси за исчерпывающую информацию.

И кто там вякал, что анонимусы на ЛОРе не нужны? :)

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

Гыгылол. В приведенной мною реализации в качестве ключей может быть любой строковый буфер, если ты до сих пор не усёк. Хоть с диска считанный, хоть юзером введенный.

«Note that neither keys nor values are copied when inserted into the GHashTable, so they must exist for the lifetime of the GHashTable. This means that the use of static strings is OK, but temporary strings (i.e. those created in buffers and those returned by GTK+ widgets) should be copied with g_strdup() before being inserted.» - читай до просветления

Единственное что, надо будет аргументик NULL в вызове g_hash_table_new_full заменить на g_free, дабы подчищать и память ключей при дестрое хэша.

«It is also not advisable to mix static strings and dynamically-allocated strings in a GHashTable, because it then becomes difficult to determine whether the string should be freed.» - и вот это еще

Дальше то что?

да ничего, думаю все и так очевидно

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

извиняюсь - просмотрел g_str_hash, да, строки тут честно сравниваются, то я просмотрел и решил, что у тебя хэш по указателям

vaino
()

А вообще Tcl\Tk, Python\Tk is a right way. Нафейхуа Вам так сразу Срр? Вы же просто пишете графический backend!

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

Так ведь наоборот же:

Решил попробовать поучить С++

Возникла идея попрактиковать.

Думаю написать графический интерфейс для одной консольной проги. Стоит ли начинать с этого?

А вообще ТС вбросил, а ни на один коммент, ни на один вопрос не ответил. То ли спит, то ли умер. :)

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

Судя по ОП, он уже где-то конпелятор спионерил и уже успел хелловорлд написать. А потом на дессерт потянуло. Люди тут уже вторую страницу из штанов выпрыгивают (чего только не понаписали), а «Васька (ТС) слушает, да ест». :)

DeVliegendeHollander ★★
()

Пишу на php (аааа.. не пинайте!!!), на js.

C++ хочу просто для тренировки мозга и для убийства времени и может пригодится :)

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

C++ хочу просто для тренировки мозга и для убийства времени и может пригодится

Ну тогда пиши то, к чему душа лежит. Вот ты говорил про графический интерфейс к консольной утилите - пиши интерфейс. Главное - не стесняться. :)

Пишу на php (аааа.. не пинайте!!!), на js.

Никто пинать не будет. Не за что.

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

последую вашему совету («пиши интерфейс»).

я просто php тоже так учил - на конкретном примере (проекте который решил сам реализовать когда возникла идея). До сих пор учусь. Мне по другому - не очень удобно.

Мне просто бывает, что-то не нравится в проге, я следую логике - «не нравится - сделай сам» ;) А в linux`e множество программ которые хотелось бы допилить.

Вот и подумываю в свободное время попробовать.

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

Ты не привёл кода Runnable

Два абстрактных метода - вот и все дела.

delete this — антипаттерн

Я так не считаю. Фактически поведение не отличается от поведение QRunnable::autoDelete, с теми же ошибками при создании объекта на стеке.

2. Создание объекта с неинициализированными полями — моветон.

Ты бы ещё за «Х» меня покритиковал.

3. Код не exception safe: new может выкинуть exception, и оно всё встанет на уши.

Я даже больше скажу - Thread тоже может выкинуть exception. Но! Сюрприз-сюрприз - меня такое поведение устраивает. Это код не для атомной подводной лодки - аварийное завершение будет лучшим решением.

Вообще же, на Це этот алгоритм был бы проще, читабельнее и короче

Ещё один - и за счет чего же?

если, как сделано у тебя, скрыть обёртку threads в отдельном модуле

Ок. Приведи код на С, такой как если бы у тебя была какая-нибудь обертка. void* == fail.

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

На самом деле основной поток завершает цикл main, после чего ждет завершения всех потоков.

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

Ок. Приведи код на С, такой как если бы у тебя была какая-нибудь обертка. void* == fail.

typedef struct
{
   int min;
   int max;
} userparams_t;

#define PAR(pname)  (((userparams_t*)(userparams))->pname)
void run(threadid_t threadid, void* userparams)
{
   for(; PAR(min) <= PAR(max); ++PAR(min))
   {
      thread_sleep(threadid, 1);
      printf("%d:::\n", PAR(min));
   }
}

int main(void)
{
   userparams_t myparams = {5, 10};
   threadid_t threadid = thread_start(&myparams, run);
   puts("end\n");
   thread_join(threadid);
   return 0;
}
anonymous
()
Ответ на: комментарий от anonymous

Нечитаемо абсолютно. void*, тут даже говорить не о чем. Как бы ты не старался - на плюсах всегда можно сделать как минимум не хуже чем на сишке. Вот кстати реализация на современном стандарте:

#include <iostream>
#include <thread>
using namespace std;

int main() {
	int i = 5;
	int max = 10;
	thread myThread (
		[&](){
				for(; i <= max; i++) {
					this_thread::sleep_for(chrono::seconds(1));
					cout<<i<<":::"<<endl;
				}
		}
	);
	myThread.join();
}
(хотя в первоначальной версии я управлял ресурсами, а здесь схалтурил)

son_of_a_gun
()

Я прочитал «Си чего начать изучение С++» :-)

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