forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   C++ (http://forum.boolean.name/forumdisplay.php?f=22)
-   -   f(const x) (http://forum.boolean.name/showthread.php?t=16975)

impersonalis 27.06.2012 01:46

f(const x)
 
Часто ли вы дополнительно "защищаете" аргументы функции, делая им каст в const, например:
Код:

void Save2File(const char* const FileName);
Гарантируя тем самым, что внутри функции значение переменной изменено не будет (в примере - и адрес, и размещённые по нему данные, но интересует только "защита" адреса).
Отдельно оговорюсь: "защита" именно копируемых данных (передаваемых по значению, а не по ссылке или через указатель), т.е. от изменения которых в вызывающем коде ничего не меняется.

HolyDel 27.06.2012 02:07

Ответ: f(const x)
 
Код:

void Save2File(const char* const FileName);
если бы мне платили за килобайты кода - защищал бы:)
а так это адов бред, имхо.

хотя больше бесит когда по константной ссылке передают всякие инты, чары и флоаты.

impersonalis 27.06.2012 02:13

Ответ: f(const x)
 
Цитата:

Сообщение от HolyDel (Сообщение 231567)
Код:

void Save2File(const char* const FileName);
если бы мне платили за килобайты кода - защищал бы:)
а так это адов бред, имхо.

хотя больше бесит когда по константной ссылке передают всякие инты, чары и флоаты.

Суть: избежать случайного затирания внутри функции.
Ну из серии: скопипастил кусок кода из старой реализации, который оперирует массивом FileName и заодно изменяет адрес, хранимый в указателе (допустим, для той задачи это было адекватно [например, указатель ссылается на последний слеш в переданном имени], а в теперешней - нет) . И бац - ошибка.
Пример синтетический конечно, но, если всё по уму писать, то многое от чего можно отказаться - некоторый контроль (особенно при коллективном программировании) можно возложить на язык.

Не думаю, что часто в реализации вы используете повторно нессылочные аргументы - так чего же их не "закрыть"?

Я не агитирую, я высказываю контраргумент для полноты картины

HolyDel 27.06.2012 02:21

Ответ: f(const x)
 
Цитата:

И бац - ошибка.
локализованная внутри одной функции :)

если ставим const - то ставим везде. или некрасиво.

в твоем же примере это было бы как то так:
Код:

void Save2File1(const char* const FileName)
{
char buff[255];
strcpy(FileName,buff,strlen(FileName)+1);
...код который ставит слеш в buff
и работает с buff
}

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

impersonalis 27.06.2012 02:35

Ответ: f(const x)
 
Приблизительно понял смесь из memcpy и strcpy, но я же писал - в новой реализации как раз не нужно что либо делать (на запись) с аргументом.
Для адресования можно просто создать новый указатель (массив, напомню, и так константный).
Код:

char* sl_ptr=FileName+х;
В то время как в скопированной реализации, бралось имя файла без учёта полного адреса, потому там адекватно использовался "аргументный" указатель:
Код:

FileName+=х;
Отсутствие "защиты" (и копипаст!) приведёт к тому, что выбравшийся из леса конструкций указатель уже будет совсем не тем, что прежде. Он по-прежнему будет ласково отзываться на своё прежнее имя, но тьма уже простёрла руку: внутри него имена всемогущей кучи.


Наличие "защиты" какбэ говорит нам: имя файла определено в рамках функции раз и навсегда. Хотите создавать свои сущности - именуйте их иначе.

Ладно: пусть это будет текущее время, переданное в функцию решения группы диф.ур-ий.

HolyDel 27.06.2012 10:26

Ответ: f(const x)
 
видимо я криво объяснил свою точку зрения. на счет копипаста она довольно проста на самом деле:

1) если у некоторых функций аргумент будет константным а у некоторых нет - то мы выносим детали реализации в интерфейс, а это говно.
2) поэтому, надо или у всех функций делать аргумент константным или у всех не делать
3) если у исходной функциии аргумент константный, то внутри находится код, который эту константность как-то обходит, и этот код будет копипаститься в новую функцию (также с константным аргументом) и успешно будет компилироваться.
4) если же у исходной функции аргумент НЕ константный, а у новой константный - то см пункт 1.

impersonalis 27.06.2012 10:44

Ответ: f(const x)
 
Цитата:

Сообщение от HolyDel (Сообщение 231592)
видимо я криво объяснил свою точку зрения. на счет копипаста она довольно проста на самом деле:

1) если у некоторых функций аргумент будет константным а у некоторых нет - то мы выносим детали реализации в интерфейс, а это говно.
2) поэтому, надо или у всех функций делать аргумент константным или у всех не делать
3) если у исходной функциии аргумент константный, то внутри находится код, который эту константность как-то обходит, и этот код будет копипаститься в новую функцию (также с константным аргументом) и успешно будет компилироваться.
4) если же у исходной функции аргумент НЕ константный, а у новой константный - то см пункт 1.

Более чем доходчиво! Стало понятно после первого прочтения.
Остался лишь риторический осадок: может стоит запрещать изменять аргументы функций, передаваемые по значению правилами языка?

HolyDel 27.06.2012 11:03

Ответ: f(const x)
 
теоретически должно быть полезно.
на практике я куда чаще сталкивался с удобством изменения параметра (было пару раз), чем с ошибками, связанными из - за его не константности (ни разу не сталкивался).

еще можно делать так (по крайней мере в студии ,не знаю насколько это по стандарту) с одной стороны остается чистый интерфейс - с другой, реализация может учитывать константным оставлять аргумент или нет.
Код:

const char* x(const char* value); //Интерфейс

const char* x(const char* const value) //реализацяи
{
        value = "begrh"; //ошибка компиляции
        return value;
}


jimon 27.06.2012 12:46

Ответ: f(const x)
 
давайте попробуем заставить llvm ( http://llvm.org/demo/index.cgi ) выдать разный код с const и без, мой пример пока даёт одинаковый код :

Код:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

uintptr_t test1(const int * a)
{
return (uintptr_t)a + 0xff;
}

uintptr_t test2(const int * const a)
{
return (uintptr_t)a + 0xff;
}

int main()
{
int a = 0, b = 0;
printf("%li\n", test1(&a));
printf("%li\n", test2(&b));
}

и выхлоп :

Код:

; ModuleID = '/tmp/webcompile/_10893_0.bc'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@.str = private unnamed_addr constant [5 x i8] c"%li\0A\00", align 1

define i64 @test1(i32* %a) nounwind uwtable readnone {
  %1 = ptrtoint i32* %a to i64
  %2 = add i64 %1, 255
  ret i64 %2
}

define i64 @test2(i32* %a) nounwind uwtable readnone {
  %1 = ptrtoint i32* %a to i64
  %2 = add i64 %1, 255
  ret i64 %2
}

define i32 @main() nounwind uwtable {
  %a = alloca i32, align 4
  %b = alloca i32, align 4
  store i32 0, i32* %a, align 4, !tbaa !0
  store i32 0, i32* %b, align 4, !tbaa !0
  %1 = ptrtoint i32* %a to i64
  %2 = add i64 %1, 255
  %3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([5 x i8]* @.str, i64 0, i64 0), i64 %2) nounwind
  %4 = ptrtoint i32* %b to i64
  %5 = add i64 %4, 255
  %6 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([5 x i8]* @.str, i64 0, i64 0), i64 %5) nounwind
  ret i32 0
}

declare i32 @printf(i8* nocapture, ...) nounwind

кодогенератор в x64 вообще интересно свернул llvm ассемблер :
Код:

.file        "/tmp/webcompile/_11162_0.bc"
        .text
        .globl        test1
        .align        16, 0x90
        .type        test1,@function
test1:                                  # @test1
.Ltmp0:
        .cfi_startproc
# BB#0:
        leaq        255(%rdi), %rax
        ret
.Ltmp1:
        .size        test1, .Ltmp1-test1
.Ltmp2:
        .cfi_endproc
.Leh_func_end0:

        .globl        test2
        .align        16, 0x90
        .type        test2,@function
test2:                                  # @test2
.Ltmp3:
        .cfi_startproc
# BB#0:
        leaq        255(%rdi), %rax
        ret
.Ltmp4:
        .size        test2, .Ltmp4-test2
.Ltmp5:
        .cfi_endproc
.Leh_func_end1:

        .globl        main
        .align        16, 0x90
        .type        main,@function
main:                                  # @main
.Ltmp7:
        .cfi_startproc
# BB#0:
        pushq        %rax
.Ltmp8:
        .cfi_def_cfa_offset 16
        movl        $0, 4(%rsp)
        movl        $0, (%rsp)
        leaq        259(%rsp), %rsi
        movl        $.L.str, %edi
        xorb        %al, %al
        callq        printf
        leaq        255(%rsp), %rsi
        movl        $.L.str, %edi
        xorb        %al, %al
        callq        printf
        xorl        %eax, %eax
        popq        %rdx
        ret
.Ltmp9:
        .size        main, .Ltmp9-main
.Ltmp10:
        .cfi_endproc
.Leh_func_end2:

        .type        .L.str,@object          # @.str
        .section        .rodata.str1.1,"aMS",@progbits,1
.L.str:
        .asciz        "%li\n"
        .size        .L.str, 5


        .section        ".note.GNU-stack","",@progbits

функции в две команды :)

HolyDel 27.06.2012 13:14

Ответ: f(const x)
 
Цитата:

выдать разный код с const и без
при чем здесь это?
Импер предлагал использовать const для обнаружения возможных ошибок на этапе компиляции, а не для оптимизации исполнимого кода :)

ffinder 27.06.2012 15:04

Ответ: f(const x)
 
импэ, переходи уже на функциональные языки - там много матана, теорката и главное (!) все переменные - неизменяемые.

Randomize 27.06.2012 22:21

Ответ: f(const x)
 
Цитата:

Сообщение от ffinder (Сообщение 231621)
переменные - неизменяемые

:super: какие же они тогда "переменные"?

ffinder 28.06.2012 00:18

Ответ: f(const x)
 
Цитата:

Сообщение от Randomize (Сообщение 231695)
:super: какие же они тогда "переменные"?

еще один пример legacy. они - значения, которые передаются в качестве параметров функций.
но! в математике переменные вовсе не меняют своих значений.


Часовой пояс GMT +4, время: 00:03.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot