1

Тема: [P3390R0] Безпечний C++

Трошки обурень топік. Якось я пропустив цю пропозицію зробити C++ безпечним. Загалом, я зовсім не проти розвитку мови у напрямку забезпечення більш комфортного та приємного досвіду роботи, зокрема шляхом розширення інструментарію мови для написання більш безпечного коду. На цю тему вже було достатньо різних пропозицій, які з тих чи інших причин були просто відкинуті комітетом, десь в кутку кімнати плаче один Герб Саттер. Але те, що пропонує [P3390R0] Safe C++ виглядає зовсім смішно, автори вирішили не заморочуватись зовсім та хочуть всунути одразу цілий Rust в C++, ну а чого ні?

Pimp My Rust++

https://imgflip.com/s/meme/Yo-Dawg-Heard-You.jpg

От, що ось це таке?

template <class T>
class slice_iterator/(a)
{
  T* unsafe p_;
  T* end_;
  T^/a __phantom_data;

public:
  slice_iterator([T; dyn]^/a s) noexcept safe
    : p_((*s)~as_pointer), unsafe end_((*s)~as_pointer + (*s)~length) { }

  optional<T^/a> next(self^) noexcept safe {
    if (self->p_ == self->end_) { return .none; }
    return .some(^*self->p_++);
  }
};

Чи ось це?

void entry_point(arc<mutex<string>> data, int thread_id) safe {
  auto lock_guard = data->lock();
  string^ s = mut lock_guard.borrow();

  s.append("*");

  println(*s);

  unsafe { std::this_thread::sleep_for(std::chrono::seconds(1)); }
}

Це ніяк не робить С++ безпечнішим, а лише ускладнює і без того, досить складну мову. Не те, що всі запропоновані там ідеї є поганими, авторів місцями переслідують непогані думки, проте вони явно швидші за них.

Подякували: leofun01, steamwater, koala3

2

Re: [P3390R0] Безпечний C++

Так, Rust дає для компенсації усіх проблем, що він додає задля безпеки, купу зручностей. А C++ і так незручний.

3

Re: [P3390R0] Безпечний C++

В C++ інтерпретувати одну й ту саму область памяті як зовсім різні структури даних я можу, а в Rust - ні.
Якою би "безпечною" мова не була, вона не "зайде" якщо не покриває базові потреби розробника.

Подякували: wander, steamwater2

4 Востаннє редагувалося koala (18.10.2024 15:37:48)

Re: [P3390R0] Безпечний C++

union IntAndBytes {
    i: i32,
    b: [u8; 4],
}

fn main() {
    let mut hack = IntAndBytes{i: 0};
    unsafe {hack.b.copy_from_slice("abcd".as_bytes())};
    println!("{}", unsafe{hack.i});
    println!("{}", unsafe{std::str::from_utf8_unchecked(&hack.b)});
}

перевірка
ЩЯРНТ?

ПОНОВА: трохи модифікував код, щоб показати, що все на одному місці

Так, на плюсах тут дійсно менше коду, ніяких unsafe і unchecked. Але ж це виразно небезпечна операція.

Подякували: leofun011

5

Re: [P3390R0] Безпечний C++

koala написав:
union IntAndBytes {
    i: i32,
    b: [u8; 4],
}

fn main() {
    let mut hack = IntAndBytes{i: 0};
    unsafe {hack.b.copy_from_slice("abcd".as_bytes())};
    println!("{}", unsafe{hack.i});
    println!("{}", unsafe{std::str::from_utf8_unchecked(&hack.b)});
}

перевірка
ЩЯРНТ?

ПОНОВА: трохи модифікував код, щоб показати, що все на одному місці

Так, на плюсах тут дійсно менше коду, ніяких unsafe і unchecked. Але ж це виразно небезпечна операція.

Оце так блоат у Rust

union IntAndBytes {
    i: i32,
    b: [u8; 4],
}

pub fn foo() {
    let mut hack = IntAndBytes{i: 0};
    unsafe { hack.b.copy_from_slice("abcd".as_bytes()) };
}
Прихований текст

Всього лиш 277 рядків

core::intrinsics::copy_nonoverlapping::precondition_check::h66731fb7d226cdc3:
        sub     rsp, 152
        mov     qword ptr [rsp + 8], rdi
        mov     qword ptr [rsp + 16], rsi
        mov     qword ptr [rsp + 24], rdx
        mov     qword ptr [rsp + 32], rcx
        mov     qword ptr [rsp + 40], r8
        cmp     rdi, 0
        jne     .LBB0_2
        jmp     .LBB0_3
.LBB0_2:
        mov     rcx, qword ptr [rsp + 32]
        mov     rax, rcx
        shr     rax
        movabs  rdx, 6148914691236517205
        and     rax, rdx
        sub     rcx, rax
        movabs  rdx, 3689348814741910323
        mov     rax, rcx
        and     rax, rdx
        shr     rcx, 2
        and     rcx, rdx
        add     rax, rcx
        mov     rcx, rax
        shr     rcx, 4
        add     rax, rcx
        movabs  rcx, 1085102592571150095
        and     rax, rcx
        movabs  rcx, 72340172838076673
        imul    rax, rcx
        shr     rax, 56
        mov     dword ptr [rsp + 144], eax
        cmp     dword ptr [rsp + 144], 1
        je      .LBB0_4
        jmp     .LBB0_5
.LBB0_3:
        jmp     .LBB0_7
.LBB0_4:
        mov     rax, qword ptr [rsp + 8]
        mov     rcx, qword ptr [rsp + 32]
        sub     rcx, 1
        and     rax, rcx
        cmp     rax, 0
        je      .LBB0_6
        jmp     .LBB0_3
.LBB0_5:
        lea     rax, [rip + .L__unnamed_1]
        mov     qword ptr [rsp + 48], rax
        mov     qword ptr [rsp + 56], 1
        mov     rcx, qword ptr [rip + .L__unnamed_2]
        mov     rax, qword ptr [rip + .L__unnamed_2+8]
        mov     qword ptr [rsp + 80], rcx
        mov     qword ptr [rsp + 88], rax
        mov     qword ptr [rsp + 64], 8
        mov     qword ptr [rsp + 72], 0
        lea     rsi, [rip + .L__unnamed_3]
        mov     rax, qword ptr [rip + core::panicking::panic_fmt::h3d8fc78294164da7@GOTPCREL]
        lea     rdi, [rsp + 48]
        call    rax
        jmp     .LBB0_18
.LBB0_6:
        mov     rax, qword ptr [rsp + 16]
        cmp     rax, 0
        je      .LBB0_8
        jmp     .LBB0_9
.LBB0_7:
        lea     rdi, [rip + .L__unnamed_4]
        mov     rax, qword ptr [rip + core::panicking::panic_nounwind::hb98133c151c787e4@GOTPCREL]
        mov     esi, 166
        call    rax
.LBB0_8:
        jmp     .LBB0_10
.LBB0_9:
        mov     rcx, qword ptr [rsp + 32]
        mov     rax, rcx
        shr     rax
        movabs  rdx, 6148914691236517205
        and     rax, rdx
        sub     rcx, rax
        movabs  rdx, 3689348814741910323
        mov     rax, rcx
        and     rax, rdx
        shr     rcx, 2
        and     rcx, rdx
        add     rax, rcx
        mov     rcx, rax
        shr     rcx, 4
        add     rax, rcx
        movabs  rcx, 1085102592571150095
        and     rax, rcx
        movabs  rcx, 72340172838076673
        imul    rax, rcx
        shr     rax, 56
        mov     dword ptr [rsp + 148], eax
        cmp     dword ptr [rsp + 148], 1
        je      .LBB0_11
        jmp     .LBB0_12
.LBB0_10:
        jmp     .LBB0_7
.LBB0_11:
        mov     rax, qword ptr [rsp + 16]
        mov     rcx, qword ptr [rsp + 32]
        sub     rcx, 1
        and     rax, rcx
        cmp     rax, 0
        je      .LBB0_13
        jmp     .LBB0_10
.LBB0_12:
        lea     rax, [rip + .L__unnamed_1]
        mov     qword ptr [rsp + 96], rax
        mov     qword ptr [rsp + 104], 1
        mov     rcx, qword ptr [rip + .L__unnamed_2]
        mov     rax, qword ptr [rip + .L__unnamed_2+8]
        mov     qword ptr [rsp + 128], rcx
        mov     qword ptr [rsp + 136], rax
        mov     qword ptr [rsp + 112], 8
        mov     qword ptr [rsp + 120], 0
        lea     rsi, [rip + .L__unnamed_3]
        mov     rax, qword ptr [rip + core::panicking::panic_fmt::h3d8fc78294164da7@GOTPCREL]
        lea     rdi, [rsp + 96]
        call    rax
        jmp     .LBB0_18
.LBB0_13:
        mov     rcx, qword ptr [rsp + 40]
        mov     rdx, qword ptr [rsp + 24]
        mov     rsi, qword ptr [rsp + 16]
        mov     rdi, qword ptr [rsp + 8]
        call    core::ub_checks::is_nonoverlapping::runtime::he089e5cfaf8f2c8b
        mov     byte ptr [rsp + 7], al
        jmp     .LBB0_15
        mov     rax, qword ptr [rip + core::panicking::panic_cannot_unwind::he9511e6e72319a3e@GOTPCREL]
        call    rax
.LBB0_15:
        mov     al, byte ptr [rsp + 7]
        test    al, 1
        jne     .LBB0_17
        jmp     .LBB0_16
.LBB0_16:
        jmp     .LBB0_7
.LBB0_17:
        add     rsp, 152
        ret
.LBB0_18:
        ud2

core::intrinsics::unlikely::hf11d1a1277c7b0e5:
        mov     al, dil
        and     al, 1
        movzx   eax, al
        ret

core::slice::<impl [T]>::copy_from_slice::h2d7dcecc35ce7fce:
        sub     rsp, 40
        mov     qword ptr [rsp], rdi
        mov     qword ptr [rsp + 8], rsi
        mov     qword ptr [rsp + 16], rdx
        mov     qword ptr [rsp + 24], rcx
        mov     qword ptr [rsp + 32], r8
        cmp     rsi, rcx
        jne     .LBB2_2
        jmp     .LBB2_3
.LBB2_2:
        mov     rdx, qword ptr [rsp + 32]
        mov     rsi, qword ptr [rsp + 24]
        mov     rdi, qword ptr [rsp + 8]
        mov     rax, qword ptr [rip + core::slice::<impl [T]>::copy_from_slice::len_mismatch_fail::ha53e432951fc4fd6@GOTPCREL]
        call    rax
.LBB2_3:
        mov     r8, qword ptr [rsp + 8]
        mov     rsi, qword ptr [rsp]
        mov     rdi, qword ptr [rsp + 16]
        mov     ecx, 1
        mov     rdx, rcx
        call    core::intrinsics::copy_nonoverlapping::precondition_check::h66731fb7d226cdc3
        mov     rsi, qword ptr [rsp + 16]
        mov     rdi, qword ptr [rsp]
        mov     rdx, qword ptr [rsp + 8]
        shl     rdx, 0
        call    memcpy@PLT
        add     rsp, 40
        ret

core::ub_checks::is_nonoverlapping::runtime::he089e5cfaf8f2c8b:
        sub     rsp, 72
        mov     rax, rdx
        mov     qword ptr [rsp + 16], rdi
        mov     qword ptr [rsp + 24], rsi
        mul     rcx
        mov     qword ptr [rsp + 32], rax
        seto    al
        and     al, 1
        mov     byte ptr [rsp + 71], al
        test    byte ptr [rsp + 71], 1
        jne     .LBB3_2
        mov     rax, qword ptr [rsp + 16]
        mov     rcx, qword ptr [rsp + 24]
        mov     rdx, qword ptr [rsp + 32]
        mov     qword ptr [rsp + 48], rdx
        mov     qword ptr [rsp + 40], 1
        mov     rdx, qword ptr [rsp + 48]
        mov     qword ptr [rsp + 8], rdx
        cmp     rax, rcx
        jb      .LBB3_4
        jmp     .LBB3_3
.LBB3_2:
        lea     rdi, [rip + .L__unnamed_5]
        mov     rax, qword ptr [rip + core::panicking::panic_nounwind::hb98133c151c787e4@GOTPCREL]
        mov     esi, 61
        call    rax
.LBB3_3:
        mov     rcx, qword ptr [rsp + 24]
        mov     rax, qword ptr [rsp + 16]
        sub     rax, rcx
        mov     qword ptr [rsp + 56], rax
        jmp     .LBB3_5
.LBB3_4:
        mov     rcx, qword ptr [rsp + 16]
        mov     rax, qword ptr [rsp + 24]
        sub     rax, rcx
        mov     qword ptr [rsp + 56], rax
.LBB3_5:
        mov     rax, qword ptr [rsp + 8]
        cmp     qword ptr [rsp + 56], rax
        setae   al
        and     al, 1
        movzx   eax, al
        add     rsp, 72
        ret

example::foo::hdd7159dab7a83506:
        push    rax
        mov     dword ptr [rsp + 4], 0
        lea     rdx, [rip + .L__unnamed_6]
        mov     ecx, 4
        lea     rdi, [rsp + 4]
        mov     esi, 4
        lea     r8, [rip + .L__unnamed_7]
        call    qword ptr [rip + core::slice::<impl [T]>::copy_from_slice::h2d7dcecc35ce7fce@GOTPCREL]
        pop     rax
        ret

.L__unnamed_4:
        .ascii  "unsafe precondition(s) violated: ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap"

.L__unnamed_8:
        .ascii  "is_aligned_to: align is not a power-of-two"

.L__unnamed_1:
        .quad   .L__unnamed_8
        .asciz  "*\000\000\000\000\000\000"

.L__unnamed_2:
        .zero   8
        .zero   8

.L__unnamed_9:
        .ascii  "/rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/ptr/const_ptr.rs"

.L__unnamed_3:
        .quad   .L__unnamed_9
        .asciz  "Q\000\000\000\000\000\000\000\031\006\000\000\r\000\000"

.L__unnamed_5:
        .ascii  "is_nonoverlapping: `size_of::<T>() * count` overflows a usize"

.L__unnamed_6:
        .ascii  "abcd"

.L__unnamed_10:
        .ascii  "/app/example.rs"

.L__unnamed_7:
        .quad   .L__unnamed_10
        .asciz  "\017\000\000\000\000\000\000\000\n\000\000\000\025\000\000"

DW.ref.rust_eh_personality:
        .quad   rust_eh_personality

С++ варіант

union int_and_bytes_t {
    int  i;
    char b[4];
};

void foo() {
    int_and_bytes_t hack;
    hack.i = 0;

    __builtin_memcpy(hack.b, "abcd", 4);
}

output:

foo():
        push    rbp
        mov     rbp, rsp
        mov     dword ptr [rbp - 4], 0
        mov     eax, dword ptr [rip + .L.str]
        mov     dword ptr [rbp - 4], eax
        pop     rbp
        ret

.L.str:
        .asciz  "abcd"

Я щось не так роблю?

koala написав:

Але ж це виразно небезпечна операція.

Гадаю leofun01 мав на увазі, що безпечно цього все одно не зробити, що в Rust, що у C++..

Подякували: leofun01, steamwater2

6 Востаннє редагувалося leofun01 (18.10.2024 16:49:22)

Re: [P3390R0] Безпечний C++

Виявилось в мене застарілий компілер для Rust. Каюсь, пішов оновити софт.

upd: а.. я згадав чому він не оновлений: пререквізити. Дякую, обійдусь.

7

Re: [P3390R0] Безпечний C++

wander написав:

Я щось не так роблю?

Так.
На будь-якому форумі по Rust вас одразу спитають: а це debug чи release? Увімкніть оптимізацію і буде вам щастя.

очевидно ж
example::foo::hdd7159dab7a83506:
        ret

8 Востаннє редагувалося steamwater (22.10.2024 12:20:26)

Re: [P3390R0] Безпечний C++

Я лише хочу ще нагадати невдалу спробу Microsoft нав'язати громадскостi такий собi "безпечний" дiалект С++ як C++/CLI, який був лише частиною бiльшого проекту MSIL i бачився iнструментом мiграцiї з C++ native. Там, доречи, була можливiсть писати змiшаний код, так само як i у текучому пропоузалi. Дуже схоже. Але тодi невдалося i C++/CLI, фактично вмер. Зостався C#. Стало очевидно, що перемiщення С++ кодерiв у "безпечний" варiант, без примусу не дiє. Тому я й припустив, цей пропоузал як початок наступної спроби, але бiльш могутньої. Може я й помиляюсь. Хотiлось би цього.
Але безпека це не тiльки бiзнес з глобальними гравцями та мегакорпорацiями типу InTel та Microsoft. Це щей омрiяна iдioма людства. Людство жадає позбавлення вiд жаху. Свiт IT та С++ як його частка не виключення. Далi хочу поговорите про саме С++ у цьому контекстi.

9

Re: [P3390R0] Безпечний C++

koala написав:
wander написав:

Я щось не так роблю?

Так.
На будь-якому форумі по Rust вас одразу спитають: а це debug чи release? Увімкніть оптимізацію і буде вам щастя.

очевидно ж
example::foo::hdd7159dab7a83506:
        ret

А, чому я б мав їх вмикати? Я лиш хотів подивитись, що Rust генерує під капотом такого коду, а не якийсь

foo:
        ret

після оптимізатора. У випадку з С++ я ж не вмикав оптимізацій. Я гадав, що можливо, щось інше пропускаю (я якийсь час тому, трохи грався з Rust'ом для загального розвитку, але ще не дуже знайомий з ним).

steamwater написав:

wander, а от менi, зовсiм не смiшно. Ця пропозицiя явно вказує на джерело, - госдеп.

Мені здається, тут трошки все навпаки. Різні ці державні установи з США, лише є жертвами (можливо не найдоцільніше слово у цьому контексті) публічного гайпу навколо безпечних мов програмування, до якого не в останню чергу причетне ком'юніті Rust'у. Зараз кожна мова намагається бути безпечною, що не є погано, але НМСД, останнім часом, це слово перетворилось в маркетинг й далеко не завжди відповідає тому, про що заявляють.

Для мене, основна проблема цієї конкретної пропозиції у тому, що вона вимагає значних змін у мові, роблячи її більш складною, а також занадто багато втупу копіює з Rust замість того, щоб знайти "С++ шлях" до безпечнішого коду. Я за інтеграцію того, що перевірене та працююче, зокрема borrow-checker'и як варіант. Але вочевидь, не вийде просто вкинути borrow-checker у С++ і сказати, що все тепер ми безпечна мова, чи що це легке вирішення всіх наших проблем. Я гадаю тут потрібен дещо глибший розбір того, що вже є, чого ще немає й потрібно додати. Щось типу, як вже згаданий мною Герб Саттер, пише у свому блозі про C++ safety, in context.

Подякували: steamwater, leofun012

10

Re: [P3390R0] Безпечний C++

Ну, наприклад, у Rust в дебажному коді вбудовані перевірки на переповнення, і ще купа різних. У релізному вони вимикаються. Звідси блоат. Це не C++, що ж поробиш, це Rust.

Подякували: wander1

11

Re: [P3390R0] Безпечний C++

steamwater написав:

Я лише хочу ще нагадати невдалу спробу Microsoft нав'язати громадскостi такий собi "безпечний" дiалект С++ як C++/CLI, який був лише частиною бiльшого проекту MSIL i бачився iнструментом мiграцiї з C++ native. Там, доречи, була можливiсть писати змiшаний код, так само як i у текучому проузалi. Дуже схоже. Але тодi невдалося i C++/CLI, фактично вмер. Зостався C#. Стало очевидно, що перемiщення С++ кодерiв у "безпечний" варiант, без примусу не дiє. Тому я й припустив, цей пропоузал як початок наступної спроби, але бiльш могутньої. Може я й помиляюсь. Хотiлось би цього.

Так, й справді було таке неподобство у вигляді C++/CLI, яке було повністю витіснене C# та існує хіба що на задвірках історії. Але я не певен, що їхньою першочерговою метою було зробити С++ більш "безпечним". Швидше через Common Language Infrastructure вони хотіли додати взаємодію (сумісність) з іншими мовами .NET, такими як C#. А, власне цей "безпечний" функціонал радше є лише побічним ефектом для забезпечення вищезгаданої сумісності.

Але дійсно, певна схожість, зокрема у деяких синтаксичних змінах з поточною пропозицією є, та й не лише.


P.S. Тему трохи підчистив та виділив в окреме обговорення, в даному розділі хотів би більше поговорити саме про С++.

Подякували: steamwater, leofun012

12 Востаннє редагувалося steamwater (23.10.2024 09:42:48)

Re: [P3390R0] Безпечний C++

wander написав:

Але я не певен, що їхньою першочерговою метою було зробити С++ більш "безпечним".

Я писав на C++/CLI досить багато. Зручно, доречi. Але не сумнiвайтеся. Managed code це safe code. Тобто unmanaged це unsafe. Цим просякнуті усi тексти MS :)

Шановне панство, я хочу побавити вас розмовою про безпеку у С++. Це буде, навiть бiльш ризикована тема вiдносно кiлькостi помiдорiв з боку опонентiв. Я хочу пiдняти питання яке вже було прекметом бурхливих дебатiв на зорi С++. Прошу зважити лише на те, що тема дуже велика i викласти iї детально i зльоту менi невдасьтся.
Посилпння у С++
Дуже гарна iдея. Але той факт, що воно зроблено константним, це помилка, - моя особиста думка. Заради того, що використання неiнiцiалiзованого посилання, - передача аргументом зокрема, неможлива (це єдиний плюс) втрачено:

  1. Можливiсть посилання бути окремим объєктом (не програмним) типу посилання. З цього слiдують тi що далi.

  2. Можливисть попереднього оголошення.

  3. Можливiсть перенаправлення посилання. Тобто будьякi операцiї над посиланням переадресовуються на цельовий объект i операцiя = теж. Це нормально. Але якщо б була окрема операцiя прирiвняння, хоча б саме для посилань, не було б цього перелiку недолiкiв.

  4. Можливiсть створення масивiв посилань.

  5. Можливiсть застосування операцiй прирiвняння для клаciв, що мiстять посилання.

Навiть того, що перелiковано, достатньо щоб зрозумiти, що цiна безпеки вийшла чималенька.
А далi ще й семантiку перемiщення повiсили на посилання. Вийшло не дуже просто.

Зараз вже неможливо швидко вiдкотити назад. Але поступово, менi здається, це можливо. Я це бачу десь так:

  1. Зробити посилання повновартим об'єктом, таким як скажiмо вказiвник.

  2. Ввести категорiю простроченого значення - Xvalue у мову. // тут можна на перших кроках користуватися rvalue посиланням.

  3. Ввести операцiю := як перемiщуюче прирівнювання.

  4. Ввести атрибут move для денотування перемiщуючих функцiй.

У стандартну бiблioтеку додати функцiю own, яка сематично аналогiчна std::move але щоб не плутати по-перше, а подруге, щоб каст був саме Xvalue, бо воно у подальшому має працювати без типу rvalue&& але сематично робить те й саме що std::move.

Тобто, конструктор перемiщення може виглядати так:

SomeClass(SomeClass &other) move // хоча можна б денотувати замicть "move" за допомогою ":="
{
    // some code
}

а перемiщуючий оператор прирiвнювання:

    SomeClass &operator := (SomeClass &other) // тут можна й не денотувати

Це дало б можливiсть перенести навантаження з посилань на операцiю перемiщення :=, та переназначати (перемiщувати) самi посилання.

Тобто:

SomeClass a, b, c(arg1, arg2, arg3);
a=b; // operator =
b:=C; // compile time failor to call operator := with lvalue C
b:=std::own(c); // Ok  operator := obj c is moved to b
a=foo_ret_SomeClass_obj(); // operator :=
SomeClass d(SomeClass{}); // move ctor

З посиланнями:

SomeClass a, b, c;
SomeClass &ra, &rb, &rc;
ra=a; // як завжди
rb=b; // теж
rb=ra; // b=a
rb:=ra; // rb посилається на a !!
++rb; // ++a :-)
// тепер можна:
SomeClass & array_refs[3];
// чи
SomeClass & array_refs1[]{a, b, c};
// чи з посиланнями, чи з посиланнями впереміш з lvalue
SomeClass & array_refs2[]{ra, rb, c};

I потреба лишається тiльки у простих посиланнях. Але вони повноцiннi объекти з повноцiнними типами.
Стара система з посиланнями && не буде заважати та працюватиме так як i зараз. Проте згодом, всi зрозумiють, що легше без них i вони пiдуть з мови iз старими проектами. Тай в довготривалих проектах увесь новий код може бути легше та зрозумiлiше написаний.
Тобто, я хотiв сказати про те, що безпека безоплатньою не буває i навiв приклад того, як могло б бути, якщо б свого часу не закортiло надiти на всiх пiдгузки.
Я написав дуже стисло, з надiєю на розумiння, але й готовий до помiдорiв))

13

Re: [P3390R0] Безпечний C++

Це загалом та згрубша те, до чого прийшли в Rust'і. Нехай мене поправлять, бо я не дуже сильний в ньому, але посилання в Rust – це фактично (розумний) вказівник з семантикою запозичень (borrowing). Тобто вони:

  • можуть бути ініціалізовано не встановленим (unset)

  • можуть бути перепризв'язані (re-bound)

  • мають власну ідентичність (розмір, позицію в пам'яті, ...)

  • можуть бути вкладеними

  • можуть бути розіменовані

А, "розумними" їх можна назвати, бо навідміну від звичайних С++ вказівників, вони є type-safe, а отже, як і посилання у C++, не можуть бути висячими або нульовими. Що робить їх безпечними/розумними вказівниками. Та у більшості випадків вони все ще поводяться як вказівники.
І власне у пропозиції яку ми тут обговорюємо хочуть додати схоже у С++:

int^ ref;   // An uninitialized borrow.
{
  int x = 1;
  ref = ^x; // *ref is dereferenced below, so ref is live.
  f(*ref);  // now ref is dead.

  int y = 2;
  ref = ^y; // ref is live again
  f(*ref);  // ref is still live, due to read below.
}

f(*ref);    // ref is live but y is uninitialized.

, де ^ є

  • ^x - mutable borrow to x

  • ^const x - shared borrow to x

  • &x - lvalue reference to x (convertible to pointer)

  • &const x - const lvalue reference to x

  • &&x - rvalue reference to x

Змінювати посилання у С++ на даному етапі така собі ідея, вони вже мають свою семантику, відмінну від вказівника і перетворювати їх назад у вказівник має мало сенсу, я б їх не став чіпати.

Подякували: steamwater1

14 Востаннє редагувалося steamwater (22.10.2024 22:01:51)

Re: [P3390R0] Безпечний C++

wander написав:

Це загалом та згрубша те, до чого прийшли в Rust'і. Нехай мене поправлять

Посилання прийшлу у С++ з АДА де вони є повновартостним типом i можуть переназначатись. I там iх декiлька ризновидiв, як i в плюсах)

wander написав:

Змінювати посилання у С++ на даному етапі така собі ідея, вони вже мають свою семантику, відмінну від вказівника і перетворювати їх назад у вказівник має мало сенсу, я б їх не став чіпати.

Розумний консерватизм це нормально. Але я не пропоную змiнювати старе. Жоден рядок старого коду не матиме проблем щоб працювати, з появою нової операцiї та декiлькох нових слiв.Може own десь конфлiкт утворе, та можна б i без нього обiйтись, розширивши функцiонал старого move (посилання && залишиться пiд ковдрою назавжди тодi, ну й нехай). Знайти нове коротке iм'я для std, не проблема, до того ж. Менi прийшло на ум own..., але не має значення яке воно буде. Чим легше набрати - тим краще)   Але новий синтаксис пiдтримуючий ту ж стару семантiку буде альтернативним старому. Головне, те що будуть доданi новi можливостi, що зробить код виразнiшим, та гнучкiшим, а кодера бiльш вiльним.

I ще раз про безпеку, - безоплатньої безпеки не буває. А шлях до бiльш безпечного є нескiнченним. Тому треба десь зупинитись. Може якiсь генiальнi iдеї й будуть мати мiсце, але це невiдомо. Робити ж з бортьби за безпеку хрестовий похід, це самогубство для таких мов як С та С++.

15

Re: [P3390R0] Безпечний C++

steamwater написав:

Посилання прийшлу у С++ з АДА де вони є повновартостним типом i можуть переназначатись.

Ні, концепція посилань не прийшла у С++ з Ada. Натомість вони еволюціонували з ALGOL 68 (з його концепцією імен) та можливо трохи Fortran (з його семантикою call-by-reference). Власне, сам Страуструп про це говорив у свому папері A History of C++: 1979−1991.

Bjarne Stroustrup написав:

However, only C, Simula, Algol68, and in one case BCPL left noticeable traces in C++ as released in 1985. Simula gave classes, Algol68 operator overloading, references, and the ability to declare variables anywhere in a block, and BCPL gave // comments.

Тому не треба тут розказувати.

steamwater написав:

Але я не пропоную змiнювати старе. Жоден рядок старого коду не матиме проблем щоб працювати, з появою нової операцiї та декiлькох нових слiв.

ABI ламати будемо чи ні? :)

Подякували: leofun011

16

Re: [P3390R0] Безпечний C++

І що, тепер буде правило семи?

17 Востаннє редагувалося steamwater (22.10.2024 22:34:40)

Re: [P3390R0] Безпечний C++

koala написав:

І що, тепер буде правило семи?

Нi, koala, - п'яти цiлком достатньо. Просто перемiщуючи функцiї, можна буде писати у двох синаксичних варiантах, на обiр. Новий буде виглядати краще, як на мене. Але використання на викликах, буде прозорiше i бiльш гарне. Потiм, згодом, потреба у старому синтаксисi вiдпала б. :)

Ні, Ada не має такої ж концепції посилань, як C++

Я не казав, що вона була такою ж. Проте, в мене пiд рукою нема його легендарної "Дiзайн та эволюцiя С++". Я подивився iчсторiчнi зауваження в його ж "Мова програмування С++", 4 видання. I про посилання там не знайшов нiчого. Але дiйсно, ADA там споминається у iнших контекстах, а до посиланнь блище всього перегузка операторiв, що взяте як iдея саме з Алгол 68. А посилання ж почалися з реалiзацiї перегрузки операторiв. То мабуть ви правi, - моя помилка)

wander написав:

ABI ламати будемо чи ні?

Нi, не будемо. Компiлятор дещо переписати доведеться, але ж компiляторщики (а у комiтетi, майже самi компiляторщики) аж по стелi, догори дригом бiгають, щоб щось iмплементувати. I роблять кориснi речи, - самi концепти якщо узяти, - дуже гарна рiч. Але, якщо б iдея їм зайшла, то бета-версiю для тестування викотили б дуже швитко, я гадаю.
А якщо ви мали на увазi угоди про виклики, то повертати посилання не важче анiж вказiвник. Доречi, пiд ковдрою часто й густо ховається вказiвник i зараз. А там де воно зараз оптимiзується (у скоупi), то й у запропонованому варiантi можна робити те ж саме. :)

18

Re: [P3390R0] Безпечний C++

steamwater написав:

Я не казав, що вона була такою ж.

Так, я невірно сформулював свою думку, виправив.

steamwater написав:

Нi, не будемо. […] А якщо ви мали на увазi угоди про виклики, то повертати посилання не важче анiж вказiвник. Доречi, пiд ковдрою часто й густо ховається вказiвник i зараз.

Ну гаразд, зробимо ми з посилання вказівник, а чим це безпечніше за те, що є зараз?

koala написав:

І що, тепер буде правило семи?

Напевно, що так. Хоча я не до кінця розібрався в тому, що вони пропонують. В них там всі приклади на їх навороченому Circle компіляторі, який типу С++ з блекджеком та ... Плюс я досі ^ сприймаю як оператор рефлексії з [P2996R7] Reflection for C++26

The Reflection Operator (^) написав:

The reflection operator produces a reflection value from a grammatical construct (its operand):

unary-expression:
      …
      ^ ::
      ^ namespace-name
      ^ type-id
      ^ id-expression

Так що, най ці хлопці думають над новим синтаксисом, бо пропозицію з рефлексією для С++26 ніхто міняти вже не буде :)

Подякували: leofun011

19

Re: [P3390R0] Безпечний C++

wander написав:

я досі ^ сприймаю як оператор рефлексії

Хай одночасно запроваджують. Тоді C++ здохне і всі перейдуть на Rust :)

20

Re: [P3390R0] Безпечний C++

koala написав:
wander написав:

я досі ^ сприймаю як оператор рефлексії

Хай одночасно запроваджують. Тоді C++ здохне і всі перейдуть на Rust :)

Не думаю, що всі перейдуть, навіть за таких умов :)

Подякували: leofun011