LINUX.ORG.RU

быстрый взгляд на C++0x


0

0

Страуструп описал вкратце улучшения, грозящие всем программёрам С++ в следующем стандарте, который должен выйти к 2009 году. Немалая толика софта под линукс пишется на С++ поэтому новость будет интересна не только разработчикам, пишущим на С++. Итак, что же нам светит:

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

Обещается опциональная сборка мусора и поддержка параллелизма. Внимание разработчиков стандарта фокусируется на расширениях, которые "меняют способ которым люди думают" (дословно!). Добавлено наиболее значительное расширение - "концепция" как "тип типов" (посредством where-выражения) и обобщенный список инициализации. Обещано, что вектора базовых типов будут работать не медленнее встроенных массивов тех же типов. В общем всё для того, чтобы сделать обощённое программирование таким же мейнстримом как объектно-ориентированное.
Также комитет по языку уже проголосовал за добавку в STL хешей, регекспов, смарт-поинтеров, генераторов случайных чисел и математических спец-функций. Появится новый тип итераторов - auto с автоопределением своего типа. Наконец-то стандартизаторы обещают уделять внимания простоте не меньше, чем гибкости но, тем не менее, не в ущерб последней.

Просьба языковой флейм не начинать, языки всякие важны, языки всякие нужны.

>>> Подробности

★★

Проверено: Pi ()
Ответ на: комментарий от svu

>О том и спич. Возможностей - море. И утонуть в них - легче легкого, особенно новичкам.

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

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

> и если index.cpp новее, то запустит пересборку вот и все. Потом выдаст страницу

вот между пересборкой и выдачей страницы мы и рестартуем весь сервер, правда? :)

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

> Единственное известное мне решение - это создание метода init

Переопределять можно и не виртуальные функции.

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

> Просто надо разделить на две разных сущности структуры и классы

Вы меня пугаете! В классических книжках по плюсам говорилось, что структуры и классы - одно и то же, только с разным уровнем доступа "по умолчанию". Теперь модно считать, что это разные вещи? И что у структур нет rtti? Я не издеваюсь, я на самом деле довольно давно не лазил в литературу по плюсам - расскажите мне плиз.

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

> Переопределять можно и не виртуальные функции.

С невиртуальными все понятно. Если f невиртуальна, ее вызов более-менее однозначен (даже если она переопределена). А вот то, что в конструкторе вызывается не реализация из окончательно конструируемого класса, а реализация из базового класса - это очень миленько.

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

> Мляяя, да здесь (на Лоре) если и есть хоть один программист и тот только для веб пишет или системные скрипты ваяет. А флейма то развели. Все дружно читаем книгу К. Чарнецки и У.Айзенкера "Порождающее программирование". Я думаю после этого у здравомыслящих людей неостанется вопросов типа: "Какой язык круче" или "За каким языком будущее".

Но-но, сюда на ЛОР много кто забегает, один Сан-ыч пол-Москвы стоит.

Зачитал главку и содержание из "Порождающее программирование" в интернет-магазине, интересные мысли толкает товарищ, надо прикупить и зачитать всю. Только эта книга больше для ДИЗАЙНЕРОВ определяющих интерфейс, не для программёров имплементирующих его, читать её чистому программёру не просто бесполезно, а опасно - такого напридумывает, что сам потом не разберётся, ему в руки надо давать предельно прозрачный и понятный интерфейс и нехрен таких людей звать быдлокодерами, одну общую работу делают с дизайнерами, а свободы для творчества у них остаётся всё равно хоть отбавляй.

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

Простите, ответ не вкурил. На всякий случай - новичок, это тот, у кого проблемы с определением "рамок разумного" - потому что он пока еще не знаком с good practices в данном языке (и, что для плюсов страшнее, еще не понаступал на грабли bad practices).

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

> C++ ничем не хуже

про "ничем" это абсолютно голословное утверждение.

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

> С невиртуальными все понятно. Если f невиртуальна, ее вызов более-менее однозначен (даже если она переопределена). А вот то, что в конструкторе вызывается не реализация из окончательно конструируемого класса, а реализация из базового класса - это очень миленько.

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

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

> О том и спич. Возможностей - море. И утонуть в них - легче легкого, особенно новичкам.

А кого, собственно, волнуют трудности новичков?

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

> Вы меня пугаете! В классических книжках по плюсам говорилось, что структуры и классы - одно и то же, только с разным уровнем доступа "по умолчанию". Теперь модно считать, что это разные вещи? И что у структур нет rtti?

"Классы С++" и "структуры С++" - одно и то же. С разными уровнями доступа по умолчанию. "Структуры С++, не являющиеся частью иерархий" и "структуры С" не отличаются ничем. В структурах, входящих в иерархию, присутствует скрытое поле указателя на таблицу виртуальных методов ( иерархия без хотя бы виртуального деструктора не есть хорошо, поэтому большинство шансов за то, что подобная таблица и указатель на неё будут). Информация о типе хранится в таблице виртуальных методов, а не в каждом объекте класса по отдельности. Доступ к ней - через тот же указатель. Если структура не является частью иерархии, то информация о типе такой структуры вообще нигде не хранится - это просто не нужно, компилятор сгенерирует саму информацию вместо кода её получения ещё на этапе компиляции.

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

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

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

> Единственное известное мне решение - это создание метода init, вызываемого после конструктора

Ну почему же... Можно вывернуться через список инициализации, к примеру. С некоторыми ограничениями.

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

Дополнить конструктор базового класса , заставив его воспринимать классо-зависимую информацию как параметр(ы).

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

Пример :

Base ( const some_class_dependent_info& info) { ... };

...

Derived ( ... ) : Base ( derived_info, ...), f1(...)

...

Надеюсь, что понятно.

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

> По-моему первокласнику известно

Дык я о том и говорю! Первокласснику известно - что это бага by design в объектной модели плюсов. Не должно быть так.

> в частности поинтер на таблицу виртуальных функций указывает на родную для деструктора/конструктора. Твоё незнание не оправдывает твоё заблуждение :).

Если б я не знал этого - разве ж я задал бы этот вопрос?;) Но в реальности это приводит к неудобствам - человек должен всегда помнить о том, чтобы не дай бог не вызвать виртуальность из конструктора (прямо или через множество вызовов) - или иметь в виду, что это будет "не настоящая" виртуальность, а виртуальность "насколько успели построить vtable" (т.е. в моем примере это будет реализация f из класса B).

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

"Структуры С++, не являющиеся частью иерархий" - гхм, это что, в языке есть такое понятие?? Ах да, оказывается, что это "структуры С++, у которых есть vtable". Здорово, т.е. получается, если у структуры есть виртуальные методы (т.е. vtable) - я могу узнать, кто она. Если нет - не могу. Я Вас правильно понял? (Да, я в курсе, что vtable один на class, не на instance). Вам не кажется эта логика несколько извращенной? А если у объекта только невиртуальные методы? Представьте, я запихал имя класса и имя метода в конфигурационный файл - и хочу в runtime создать объект и вызвать метод?

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

>int factorial (const int n) { return n == 0 ? 1 : n * factorial (n - 1); }

>P.S. Гуляй вася, жуй опилки

Нафига тут стока скобок?

зацени:

factorial 1 = 1

factorial n = n*factorial(n-1)

чуешь, самое длиное - название функции, обалдеть, да?

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

А какая связь? "Не буду вызывать виртуальную _функцию_ дочернего класса, потому что его _мемберы_ еще не инициализированы". В огороде бузина, в Киеве Газпром. Может, моей виртуальной функции 100 лет не сдалось доступаться к мемберам дочернего класса?

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

Да, понял, параметризация через конструктор. Если параметры укладываются в элегантную и осмысленную структуру - да, может выглядеть приемлемо. Если их много и они мало связаны - немного ugly получается. Хотя, в принципе, да, можно и так. Правда, функциональный полиморфизм в общем случае так делать не очень удобно (придется запихивать в инициализационную структуру указатели на функции).

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

В случае с именем класса в конфиге без нее вообще наверное туго.

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

> Здорово, т.е. получается, если у структуры есть виртуальные методы (т.е. vtable) - я могу узнать, кто она. Если нет - не могу. Я Вас правильно понял?

Неправильно. Если у структуры нет виртуальных методов, то компилятор знает, кто она, ещё на этапе компиляции. Нет никакой нужды лезть в runtime в таблицу виртуальных методов.

> А если у объекта только невиртуальные методы?

То тип такого объекта будет считаться известным на этапе компиляции.

> Представьте, я запихал имя класса и имя метода в конфигурационный файл - и хочу в runtime создать объект и вызвать метод А зачем Вам для этого rtti? Может, это я такой глупый, но мне всегда казалось, что rtti нужен для распознавания существующего объекта, а отнюдь не для создания нового.

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

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

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

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

Соббсно, к чему я это все - к тому, что в плюсах rtti и reflection убогенькие. По сравнению с той же ругаемой всеми жабой (хотя и жаба, наверняка, не идеал в этом вопросе). Да и при байндингах в другие языки (даже ОО) rtti теряется сразу же...

svu ★★★★★
()

А компилятор для этого франкенштейна нормальный напишут к 2015...

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

> Если у структуры нет виртуальных методов, то компилятор знает, кто она, ещё на этапе компиляции

Не всегда. Таки бывает наследование без виртуальности. Нечасто, но бывает (считайте, что объекты класса всегда выделяются на стеке, так что виртуальный деструктор нафиг не нужен). И вот во глубине невиртуального метода базового класса объект внезапно задумывается: "Кто же я?..."

> А зачем Вам для этого rtti? Может, это я такой глупый, но мне всегда казалось, что rtti нужен для распознавания существующего объекта, а отнюдь не для создания нового.

Сорри, я запихал в одну кучу сразу много вещей, rtti+reflection+... Но суть не меняется - динамическая работа с типами в плюсах слаба. В качестве решения тут предложили использовать фабрики - но плюсы мало помогают в их реализации %(

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

Ну, тут и rtti не особо нужен - может хватить и обычных виртуальных функций. Даже если действия производить надо над другими объектами (их же можно передать виртуальным функциям).

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

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

если нужны извраты с вызом виртуальных функций в конструкторах, то закрывай (private) конструктор и создавай объекты статическим public методом. То есть делай что-то типа


MySuperPuperClass * object = MySuperPuperClass::Create();

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

Угу. Но в реализации этого Create таки придется вызывать сначала конструктор, потом init. Ну или передавать параметры, как тут советовали.

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

это наверное подходит и для обсуждаемого здесь интерпретатора 8)
на каждый класс по soшке 8)

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

> Таки бывает наследование без виртуальности. Нечасто, но бывает (считайте, что объекты класса всегда выделяются на стеке, так что виртуальный деструктор нафиг не нужен). И вот во глубине невиртуального метода базового класса объект внезапно задумывается: "Кто же я?..."

Извини, но это бред. B::f() всегда знает, что (он -- method, она -- function, кто из них? :) принадлежит B, поскольку не виртуален(-на).

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

Великолепно. Чисто Лоровский ответ. Господа, что за дурная привычка, чуть что, переходить на крик. Многие языки (если не сказать все) поддерживают мультипарадигменные стили прогрсммирования. И я не утверждал что Lisp является иключительно функциональным языком, перечитайте мой пост еще раз, может до вас дойдет что именно я имел ввиду. А в подтверждение воих слов приведу лиш выдержку из статьи "Лисп" с сайта http://ru.wikipedia.org/wiki.

"Лисп (LISP, от англ. «List Processing» — «обработка списков») — первый язык программирования, поддерживающий функциональную парадигму программирования. Нетипизирован, содержит массу императивных свойств, однако в общем поощряет именно функциональный стиль программирования. При вычислениях использует «вызов-по-значению»."

А теперь скажите где я наврал. Только пожалуйста без фанатизма. Я не стремлюсь здесь кого-то обидеть или ущемить в правах.

З.Ы. А что касается встраиваемых систем, то все что мне удавалось найти по поводу использования Lisp-а, это использование его в рамках проектов по разработке AI (что кажется весьма логичным). Но самые маленькие компьютеры на которых эти проекты функционировали были PC, не о какой встраиваемости речи и не идет. Более того большинство проектов использующих Lisp чисто академические и существуют в рамках НИР или исследовательских Грантов для Европейских (в основном) Университетов. Ну так и что? ЕвроУниверы славятся своей любовью использования не стандартных языков, особенно когда это не ограничено в рамках ТЗ. Одни мои знакомые ребята, работают в Технопарке при Университете "ЛЭТИ" (Санкт-Петербург) и совместно с немцами, помоему, работают над проектом AI на Java. А вот сможете ли вы мне показать реализацию компилятора Lisp для хотябы одного из массы существующих сигнальных процессоров или микроконтроллеров, тогда мы с вами и поговорим о применеии этого языка во встраиваемых системах.

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

Сам-то метод принадлежит B. А вот вызвать его могли для объекта типа D. Вопрос в том, чтобы точно определить тип объекта this.

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

По поводу виртуальных функций в конструкторе. Думается мне, что априори базовый класс не должен доверять производным, мало ли что там реализует производный. Отсюда мораль: надо вызвать явно B::f(), если есть необходимость вызывать f() вообще. Если же за каким-то фигом нужна D::f() в конструкторе B, то, кроме как, отложить завершение конструирования на вызов какой-нибудь B::finishConstructor() даже нет идей. Просто придумать зачем такое надо не могу, но может и правда надо?...

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

> Сам-то метод принадлежит B. А вот вызвать его могли для объекта типа D. Вопрос в том, чтобы точно определить тип объекта this.

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

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

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

Э-э... Т.е. виртуальные функции можно вызывать только "снаружи", вне определяющих их классов? В принципе, любопытная мысль - но, мне кажется, несколько оверкилл. И уж явно сам язык нигде такого не запрещает...

> кроме как, отложить завершение конструирования на вызов какой-нибудь B::finishConstructor() даже нет идей

Это как раз тот самый init, только с другой стороны;)

> Просто придумать зачем такое надо не могу, но может и правда надо?...

На вскидку примера не дам - но попадалось...

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

Ну блин, удоры, к сожалению, были, есть и будут... :-((

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

>Ну, если человек маньяк, решил написать программу 3D-рендеринга на Питоне - на здоровье, пиши, только не говори, что все языки сакс, Питон рулит и может эффективно использоваться для таких задач, ведь посмотрите, я же написал!

Ой ну до чего же ты тупой! Иди посмотри на Blender и убей себя.

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

> Вопрос второй. Оцените легкость поддержки кода, наполненного по делу и не по делу перегруженными операторами.

И все из-за невозможноси определения новых операторов и их приоритета и ассоциативности. (Как, скажем, в Haskell).

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

Да их вообще лучше не надо б. Мощь страшная. Чреватая страшным геморроем в поддержке

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

> При том, что эта реализация кушает память O(n), а приведенная на лиспе - O(1)

И что? Хочешь сделаю такую же реализацию на С/С++, только без дебильного goto?

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

> Нетипизирован

Ложь. Типизация динамическая

> однако в общем поощряет именно функциональный стиль программирования

Гы. setf, CLOS, отдельное пространство имен для функций и необходимость funcall, конечно очень поощрают функциональьный стиль. Лисп настолько же функциональный, насколько С++ ОО.

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

Мне друг как-то показывал реализацию факториала на шаблонах, которая считалась во время компиляции(разумеется только для констант) и сложность у нее o(0) 8).

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

А хечешь я на лиспе приведу чисто функциональную реализацию, с сложностью по памяти O(1)?

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

На шаблонах:

/*
 * compiletime-factorial.cc - Two metaprograms computing factorial at
 *                            compile-time
 */
//------------------------------------------------------------------------------

#include <iostream>
//------------------------------------------------------------------------------

template<unsigned int x>
struct fact_v1
{
  static const unsigned int res = x * fact_v1<x - 1>::res;
};

template<>
struct fact_v1<0>
{
  static const unsigned int res = 1;
};
//------------------------------------------------------------------------------

template<unsigned int x>
class fact_v2
{
  template<int y, int acc>
  struct iter
  {
    static const unsigned int res = iter<y - 1, acc * y>::res;
  };

  template<int acc>
  struct iter<0, acc>
  {
    static const unsigned int res = acc;
  };
public:
  static const unsigned int res = iter<x, 1>::res;
};
//------------------------------------------------------------------------------

const unsigned int fact15 = fact_v1<15>::res;
const unsigned int fact5 = fact_v2<5>::res;
//------------------------------------------------------------------------------

int main()
{
  std::cout << fact15 << std::endl
	    << fact5 << std::endl;
}
//------------------------------------------------------------------------------



Хотите на макрах приведу?

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