Я бачу тут кілька вагомих відповідей, але я збираюся трохи детальніше розібратися.
Перейдіть до наведеного нижче резюме, щоб отримати відповідь на своє головне питання, якщо ви не хочете пройти всю цю текстову стіну.
Абстракція
Отже, у такому випадку, за що я плачу?
Ви платите за абстракцію . Уміння писати простіший і більш дружній для людини код - це дорога ціна. У C ++, що є об'єктно-орієнтованою мовою, майже все є об'єктом. Коли ви використовуєте будь-який об'єкт, під кришкою завжди будуть три основні речі:
- Створення об'єкта, в основному розподіл пам'яті для самого об'єкта та його даних.
- Ініціалізація об'єкта (зазвичай за допомогою якогось
init()
методу). Зазвичай розподіл пам'яті відбувається під кришкою, як перше, на цьому кроці.
- Руйнування об'єкта (не завжди).
Ви не бачите його в коді, але кожен раз, коли ви використовуєте об'єкт, всі три вищезгадані речі повинні відбуватися якось. Якби ви все робили вручну, код, очевидно, був би набагато довшим.
Тепер абстракцію можна зробити ефективно, не додаючи накладні витрати: метод вбудовування та інші методи можуть використовуватися як компіляторами, так і програмістами для видалення накладних витрат абстракції, але це не ваш випадок.
Що насправді відбувається в C ++?
Ось вона, розбита:
- The
std::ios_base
Клас инициализируется, який є базовим класом для всього I / O пов'язані між собою .
- The
std::cout
Об'єкт инициализируется.
- Ваша рядок завантажується і передається в те
std::__ostream_insert
, що (як ви вже з'ясували за назвою) - це метод std::cout
(в основному <<
оператор), який додає рядок до потоку.
cout::endl
також передається в std::__ostream_insert
.
__std_dso_handle
передається в __cxa_atexit
, що є глобальною функцією, яка відповідає за "очищення" перед виходом з програми. __std_dso_handle
сама покликана цією функцією для розселення та знищення інших глобальних об'єктів.
Отже, використовуючи C ==, нічого не платячи?
У коді С відбувається дуже мало кроків:
- Ваша рядок завантажується та передається
puts
через edi
реєстр.
puts
називається.
Ніде об'єктів немає, отже, не потрібно нічого ініціалізувати / знищувати.
Це , однак , не означає , що ви не «платити» за що в C . Ви все ще платите за абстракцію, а також ініціалізацію стандартної бібліотеки С та динамічну роздільну здатність printf
функцією (або, власне,)puts
, оптимізована компілятором, оскільки вам не потрібна будь-яка рядка формату), все ще відбувається під кришкою.
Якби ви писали цю програму чистою збіркою, вона виглядала б приблизно так:
jmp start
msg db "Hello world\n"
start:
mov rdi, 1
mov rsi, offset msg
mov rdx, 11
mov rax, 1 ; write
syscall
xor rdi, rdi
mov rax, 60 ; exit
syscall
В основному це призводить лише до виклику write
syscall, за яким слід exit
syscall. Тепер це був би найменший мінімум, щоб здійснити те саме.
Узагальнити
C - це набагато голіше , і це лише мінімальний необхідний мінімум, залишаючи повний контроль користувачеві, який здатний повністю оптимізувати та налаштувати все, що завгодно. Ви говорите процесору завантажити рядок у реєстр, а потім викликаєте функцію бібліотеки, щоб використовувати цей рядок. З іншого боку, C ++ є набагато складнішим та абстрактнішим . Це має величезну перевагу при написанні складного коду та дозволяє простіше писати та більш дружній для людини код, але це, очевидно, коштує. Завжди буде недолік продуктивності в C ++, якщо порівнювати з C у таких випадках, оскільки C ++ пропонує більше, ніж потрібно для виконання таких основних завдань, і, таким чином, це додає більше витрат .
Відповідаючи на ваше головне питання :
Я плачу за те, що не їмо?
У цьому конкретному випадку так . Ви не використовуєте нічого, що C ++ може запропонувати більше, ніж C, але це лише тому, що немає нічого в тому простому фрагменті коду, який C ++ міг би вам допомогти: він настільки простий, що C ++ вам взагалі не потрібен.
О, і тільки ще одне!
Переваги C ++ можуть не здаватися очевидними на перший погляд, оскільки ви написали дуже просту і невелику програму, але подивіться на трохи складніший приклад і побачите різницю (обидві програми роблять точно те саме):
C :
#include <stdio.h>
#include <stdlib.h>
int cmp(const void *a, const void *b) {
return *(int*)a - *(int*)b;
}
int main(void) {
int i, n, *arr;
printf("How many integers do you want to input? ");
scanf("%d", &n);
arr = malloc(sizeof(int) * n);
for (i = 0; i < n; i++) {
printf("Index %d: ", i);
scanf("%d", &arr[i]);
}
qsort(arr, n, sizeof(int), cmp)
puts("Here are your numbers, ordered:");
for (i = 0; i < n; i++)
printf("%d\n", arr[i]);
free(arr);
return 0;
}
C ++ :
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(void) {
int n;
cout << "How many integers do you want to input? ";
cin >> n;
vector<int> vec(n);
for (int i = 0; i < vec.size(); i++) {
cout << "Index " << i << ": ";
cin >> vec[i];
}
sort(vec.begin(), vec.end());
cout << "Here are your numbers:" << endl;
for (int item : vec)
cout << item << endl;
return 0;
}
Сподіваємось, ви чітко бачите, що я тут маю на увазі. Також зауважте, як у C ви повинні керувати пам'яттю на нижчому рівні, використовуючи, malloc
і free
як вам потрібно бути більш уважними щодо індексації та розмірів, і як вам потрібно бути дуже конкретними при введенні даних та друку.