LINUX.ORG.RU

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

>Ну итераторы вообще-то тоже изменяются, то есть являют собой переменные. Или нет?

Ну да. И ничего особо плохого в них нет (хотя от приятного for each я бы не отказался, особенно с лёгким распаралеливанием как в OMP и с захватыванием сразу по нескольку элементов для лёгкого внедрения sse и подобного, мммм)

К сожалению, из-за перегрузки конструкторов может случайно вызваться не тот конструктор

Возможно только в теории. На практике конструкторы всегда либо сильно различаются параметрами, либо слабо различаются содержимым (rational::rational(int/float arg) { /*...*/ })

Это наверное сознательное отстреливание себе яиц, да?

Это незначительные неудобства. Да, я бы не отказался и от инициализации структур, как в новом си, и он именованных агрументов при вызове функции, как VB, например. Но отсутствие всего этого не создаёт жутких тормозов и/или часов отладки, как в некоторых других языках.

внесли опциональную возможность и обязали ей пользоваться

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

раздувая вербозивность

Уж плюсы то не самый болтливый язык.

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

>Или вам не нравиться, что константный объект инициализируется только в конструкторе?

В новом стандарте планируют ввести «значения по умолчанию» для членов класса, константных и нет. Типа так:

class C
{
char c1 = '\n';
int v1;
float v2 = 3.14;
С(int arg) : v1(arg){assert(c1=='\n' && fabs(v2-M_PI)<0.01);}
};
legolegs ★★★★★
()
Ответ на: комментарий от legolegs

>Если так плохо дело, то не пользуйся STL, пиши велосипед.

Вот, пришли к единственному более-менее вменяемому применению const: согласованность со стилем кодирования стандартной библиотеки. Но код не использующий const тоже обладает таким свойством «инвазивности».

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

Сам компилятор в гарантию константности не верит. Он смотрит конечно за тем чтобы const-переменные не оказывались слева от оператора присваивания, но сам ожидает что они будут изменяться из-за pointer aliasing.

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

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

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

const — это средство документирования.

Константный метод какбэ говорит своему пользователю «если ты вызовешь меня, то объект не будет видимым для тебя образом изменён. Поведение объекта останется неизменным»

Локальная константа в функции — классный способ как-то поименовать промежуточный результат вычислений, для себя и для будущих поколений, и не использовать звездец вроде:

вызов1(вызов2(вызов3(что-то1), вызов4()), вызов5(что-то2), вызов6());

Константа в качестве параметра (указатель на константу, константная ссылка) средство сказать «Я не собераюсь менять значение этого параметра»

Глобальная константа — средство поименовать какое-то магическое значение с использованием безопасности типов.

То, что пользователь класса/функции/библиотеки способен игнорировать эту информацию говорит только о том, что такой пользователь сознательно игнорирует часть документации.

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

но сам ожидает что они будут изменяться из-за pointer aliasing.

Комипилятор позволит присвоить указатель на константный объект, когда указатель объявлен как не на константный? Шутите?

Неплохо бы для начала изучить о чем идет речь.

int i = 42;
const int& j = i;
i = 13; // j has been changed 

Пример конечно тривиальный, т.к на практике присваивание вида i = 13 будет иметь место в другой единице трансляции. Поэтому при генерировании кода после каждого вызова метода из другой единицы трансляции следует полагать что указатели и ссылки на const теперь указывают на изменившиеся данные и их надо выфетчить заново.

Absurd ★★★
()
Ответ на: комментарий от Absurd
int i = 42; // я имею право менять этот объект в дальнейшем
const int& j = i; // я отказываюсь от права менять этот объект в дальнейшем. Мне надо только чтение.
i = 13; // j has been changed (тем, кто имел на это право)

Я чёт не вижу здесь const-violation

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

>Неплохо бы для начала изучить о чем идет речь.
Вы перевернули всё с ног на голову. Вы объявили неконстантный объект и хотите запретить его модификацию?

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

По-моему вы высосали проблему из пальца. Я ещё раз повторяю, язык лишь помогает. От дурной головы никакой язак не спасёт.

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

>>Неплохо бы для начала изучить о чем идет речь.

Вы перевернули всё с ног на голову. Вы объявили неконстантный объект и хотите запретить его модификацию?

Я привел основной use-case использования const: создание Read-Only среза неких данных. Как видим, у компилятора нет никаких оснований надеяться что этот R/O срез не будет изменяться «сам по себе».

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

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

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

>А кто-то ожидал, что данные переданные по ссылке на константу не будут изменяться в период существования владельца неконстантного объекта на который указывает ссылка??

Ну никто и не ожидает. Нужно что-то отдать наружу - клонируют просто и все. Только зачем тогда нужен const, если клиент все равно работает с копией?

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

Вы по-моему путаете, компилятор даёт гарантии на уровне имён, но ни как не на уровне самих объектов. Гарантии на уровне имён это и есть помощь компилятора. Я хочу менять объект в одном месте и не хочу в другом, и хочу чтобы компилятор помог мне в этом. Что ещё нужно? Чтобы компилятор кормил с ложечки и подтирал зад? У вас довольно странные взгляды.

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

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

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

>Абсурд, мне кажеться, ты говоришь, что плюссовый конст спецификатор не делает чего-то полезного и потому бесполезен. Если это так, то поведай же нам, что именно, по-твоему, дожен делать конст спецификатор в плюсах.
Полагаю чтобы сработал эксепшн, при доступе к конст объекту. ^)

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

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

Посмотри нормальный императивный код на той же жабе - Jetty (mortbay.org) например. Никакого фана с конструкторами, перегруженными операторами, const, и пр. Только долбаная унылая логика относящаяся к задаче которую надо решить.

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

>Посмотри нормальный императивный код на той же жабе
Так это концептуально разные языки. С++ общего назначения, хочешь пиши драйвера, хочешь прикладные программы. Жаба же чисто прикладная. Всегда специализированное, лучше подходит для своей задачи. И жаба гораздо более рантаймовая, отсюда и другие подходы.

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

/xref/org/mortbay/proxy/AsyncProxyServlet.html#138

             final InputStream in=request.getInputStream();
             final OutputStream out=response.getOutputStream();
             final Continuation continuation = ContinuationSupport.getContinuation(request,request);
Пук защитан.

Абсурд, тебе же сказали, const больше для человека, чем для машины (хотя бывают и оптимизации на основе константности, да). Правильное применение const (т.е. везде, где удаётся) позволяет запретить большое количество неправильный действий. Если писать программу с const, private и ещё несколькими простыми правилами, за которыми я отсылаю к нелюбимому тобой Страуструпу, то раз в неделю можно взять и написать кусок кода спьяну, с устатку или в спешке и оно либо заработает либо не скомпилится. Очень приятно, когда можно положиться на железный мозг. Работать проще.

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

>/xref/org/mortbay/proxy/AsyncProxyServlet.html#138

С тех пор как проект принял FOSS-совместимую лицензию стиль кодирования видно поплыл. Лучше конечно изучать более ранний релиз.

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

Вышесказанная проблема с перегруженными конструкторами в C++ существует, тот же подход Objective-C с его initWith... мне нравится гораздо больше. В своём коде я вообще избегаю перегруженных методов, гораздо читабельнее и безопастнеее будет:

int valueForChar( char ch ) const;
int valueForString( const std::string & string ) const;

чем

int value( char ch ) const;
int value( const std::string & string ) const;

В случае конструкторов для примитивных классов (с глубоким копированием данных) или с общими данными или с запрещённым конструктором копирования (использование по указателю) часто делают статические инициализаторы:

class A
{
public:
    static A fromValue( int value );
};

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

Такой подход позволяет практически любую переменную сделать константной без пенальти в скорости работы.

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

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

> int valueForChar( char ch ) const;

int valueForString( const std::string & string ) const;


ИМХО - это лишнее, мне компилятор и так скажет, если есть неоднозначность( я педантичен и вычищаю все варнинги gcc ни msvc + делаю статичную проверку кода )

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

Добавили compile-time-гарантий и «стиль поплыл». ROTFLMAOSTC! Куда-же он поплывёт, ежели ты весь фарватер расплескал своей динамической иммутабельностью.

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

>часто делают статические инициализаторы:

А вот спасибо, ты мне напомнил. Я давно хотел сравнить производительность этого дела, вот и сравнил:

#include <algorithm>
#include <cstdlib>
#define LEN(x) (sizeof(x)/sizeof(x[0]))
using namespace std;

const unsigned OPS = 4000000000;
const unsigned arrlen = 1000;
class Class
{
	int arr[arrlen];
	string shit;
	Class(){}
public:
	Class(int (*generator)())
	{
		generate(arr,arr+LEN(arr),generator);
		shit = __PRETTY_FUNCTION__;
	}
	static Class ClassCreate(int (*generator)())
	{
		Class c;
		generate(c.arr,c.arr+LEN(c.arr),generator);
		c.shit = __PRETTY_FUNCTION__;
		return c;
	}
};

int main()
{
	const unsigned count = OPS/arrlen;
	for (unsigned i=count;i>0;--i)
	{
#ifdef CTORMODE
		Class c(rand);
#endif
#ifdef RETMODE
		Class c = Class::ClassCreate(rand);
#endif
	}
}

Замеры для обоих дефайнов:

real    0m52.544s
user    0m52.527s
sys     0m0.003s

real    0m52.619s
user    0m52.608s
sys     0m0.004s
Где кто - угадывайте сами.

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

Где кто - угадывайте сами.

В зависимости от компилятора/платформы результат может быть как в пользу первого, так и второго. Какой он у вас мы узнаем, только если вы сами признаетесь.

Увеличил размер int arr[] с 1000 до 10000 и проверил на MSVC 2008 ExpressEdition SP1:

ctor time = 27697
stat time = 26639

ctor - инициализация конструктором, stat - функцией. Как видим, инициализация функцией даже быстрее, как минимум потому что компилятор сам инлайнит её тело.

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

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

В моём сообщении, на которое ты отвечаешь, не сказано, что язык C++ кривой. Он кривой, но не надо отвечать на то, что не сказано.

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

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

Ну ё-моё...

// библиотечная функция, которую писал совсем даже не я
// у меня даже исходников нет
void blablabla(const Foo *foo){
...
Foo *bar = const_cast<Foo*>(foo);
...
}

//функция, которую я сейчас пишу
const Foo *baz;
...
blablabla(baz);

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

Ужасы какие, а еще там такое может быть :))))))

// библиотечная функция, которую писал совсем даже не я 
// у меня даже исходников нет 
void blablabla( const char* foo )
{
  char* ptr;
  ptr[ 0 ] = foo[ 0 ]
}

//функция, которую я сейчас пишу 
const Foo *baz; 
... 
blablabla(baz); 
lester ★★★★
()
Ответ на: комментарий от Miguel

>В моём сообщении, на которое ты отвечаешь, не сказано, что язык C++ кривой. Он кривой, но не надо отвечать на то, что не сказано.
В ответе, я не могу ничего добавить от себя? Спасибо буду знать.

Он кривой, но не надо отвечать на то, что не сказано.

Имхо добавлять не забывайте.

Вообще если const только фан, то и проверка типов тоже только фан. Она же работает только в компайл тайме, а для некоторых это ничего не значит. Это работает для кода который пишишь только сейчас. ^)

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

>// библиотечная функция, которую писал совсем даже не я

// у меня даже исходников нет

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

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

Они защищают от того, что данные не могут измениться с помощью конкретно этих указателей и ссылок.

Ну ё-моё...

И дальше идёт пример, подтверждающий, что с помощью переменной foo изменить данные нельзя. Сколько уже раз повторялось, в C++ прямой доступ к памяти процесса, имея адрес можно на этапе выполнения делать с ним всё что угодно. Прикастировать к чему угодно и записать любой мусор, в том числе и выйдя за пределы типа. И да, для этого не нужны ни const_cast, ни C++. И ещё много раз повторялось, что const - защита на этапе компиляции. Что вы хотели сказать своим примером - совершенно не ясно.

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

Да, уже писали что защита на уровне имён, а не объектов. Вам нужно в ясли, там кормят с ложечки, подтирают зад и не дают писать ахинею.

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

>Добавили compile-time-гарантий и «стиль поплыл».

Начнем с того, что in это вообще неиспользуемая переменная. Далее, out и continuation сделаны final чтобы можно было их захватить из анонимного класса унаследованного от HttpExchange. Анонимных классов и захвата локальных const-переменных в С++ я так понимаю нет.

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

>В зависимости от компилятора/платформы результат может быть как в пользу первого, так и второго

Да вообще-то они равны. Вопрос был риторический.

Увеличил размер int arr[] с 1000 до 10000

Да, времена выполнения равны при любых длинах arr.

Как видим, инициализация функцией даже быстрее

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

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

Потери могут быть на вызове оператора копирования, если функция не инлайновая. В указаном примере функция инлайнится, поэтому никакой разницы в скорости при любом размере массива arr. Дело в том что компилятор заменяет визуальный оператор копирования:

std::string s = std::string("hello");

на конструктор:

std::string s("hello");

В случае с неинлайновым статическим инициализатором теоретически потери могут быть. На практике же часто используют auto_ptr с указателями и shared классы, поэтому даже не стоит заморачиваться.

Погрешность измерений.

Увы. Выигрыш оказывается всегда в пользу статической функции, если убрать вызов rand() думаю получим ещё более ощутимую разницу. За ответами нужно смотреть в ассемблер.

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

>Начнем с того, что in это вообще неиспользуемая переменная

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

сделаны final чтобы можно было их захватить

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

Анонимных классов и захвата локальных const-переменных в С++ я так понимаю нет.

Анонимные классы есть, а вот захвата действительно нет. Может портируют расширение «Nested Functions» из си, тогда не только константы можно будет захватывать.

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

>Потери могут быть на вызове оператора копирования

А от тут не нужен. Тут очень простая оптимизация: main() выделяет на стеке место для Class, следом кладёт параметр для ClassCreate и вызывает. ClassCreate знает, что выше параметров на стеке ей уже подготовлено местечко для возвращаемого значения и свой Class конструирует прямо там, модифицирует и делает ret без всякого копирования.

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

>>Начнем с того, что in это вообще неиспользуемая переменная

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

Ничего не поделаешь, это FOSS. Типичный FOSS-проект на С++ это вообще помойка.

сделаны final чтобы можно было их захватить

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

Каким раком захват final-переменных стал опциональной возможностью?

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

>А зачем нужна абстракция, что такое «разделение данных» и зачем оно нужно?

А разве подписывался на проведение лекции для школьников? Правильно - Нет.

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

>>А зачем нужна абстракция, что такое «разделение данных» и зачем оно нужно?

А разве подписывался на проведение лекции для школьников? Правильно - Нет.

Нет, ты уж напиши что и от чего ты пытаешься отделить.

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

>>Нет, ты уж напиши что и от чего ты пытаешься отделить.

Ну, что ты как маленький:))

Хватит ломаться. Как девочка прямо.

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

>Каким раком захват final-переменных стал опциональной возможностью?

Опциональным является использование «final». Но совершенно непонятно, почему финальность обязательна для захвата. Впрочем, куча странных ограничений - фирменная черта java.

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

>Впрочем, куча странных ограничений - фирменная черта java.

Речь какбе шла о том что в С++ локальные переменные вообще захватить нельзя. Хоть const, хоть volatile, любые вообще. Или это не странное, а истинно православное ограничение?

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

> Речь какбе шла о том что в С++ локальные переменные вообще захватить нельзя.

в С++ вообще практически все что угодно можно, хотите про это поговорить?

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

$ cat ./bozo.c++ 
#include <cstdio>

int main() {
	const int i = 42;
	struct BoZo {
		void test () {
			std::printf("%i\n", i);
		}
	};
	BoZo().test();
}

$ g++ ./bozo.c++ 
./bozo.c++: In member function ‘void main()::BoZo::test()’:
./bozo.c++:7: error: use of ‘auto’ variable from containing function
./bozo.c++:4: error:   ‘const int i’ declared here

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

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

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

>./bozo.c++:7: error: use of ‘auto’ variable from containing function ./bozo.c++:4: error: ‘const int i’ declared here

Что тебе непонятно?

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