Learn C++ STL

lesson ৭ / ৯ · C থেকে যতটুকু C++ দরকার

Module ১ · C থেকে যতটুকু C++ দরকার

std::, namespace আর যে header-গুলো সত্যিই include করবে

Freeপড়া

এই lesson-এ যা শিখবে

  • Namespace কী, সেটা বলতে পারবে, নিজের দুইটা namespace লিখতে পারবে, আর :: দিয়ে তার ভিতরের কোনো নামে পৌঁছাতে পারবে।
  • std::, একটা using-declaration আর using namespace std;-এর মধ্যে বেছে নিতে পারবে, আর শেষেরটা কেন কখনো header-এ যায় না, সেটা বলতে পারবে।
  • এই track যত standard নাম ব্যবহার করে, প্রতিটার header বলতে পারবে, আর <bits/stdc++.h> কেন শুধু GCC-তে চলে, সেটা বুঝিয়ে বলতে পারবে।

Bob-এর contest program শুরু হয় #include <bits/stdc++.h> দিয়ে, আর Playground-এ সেটা দিব্যি compile হয়, pass-ও করে। Maria program-টা নিজের Mac-এ নিয়ে যায়, যেখানে compiler হলো clang, তার নিজের library সহ, আর প্রথম লাইনেই আটকে যায়: fatal error: 'bits/stdc++.h' file not found। Program-এ কোনো ভুল নেই, তবু এক compiler নেয়, আরেকটা নেয় না। কেন, সেটা বুঝতে দুইটা জিনিস জানা লাগবে: একটা standard নাম থাকে কোথায়, আর কোন file সেটা তোমার program-এ নিয়ে আসে। এই lesson দুইটাই দেবে, সাথে হাতের কাছে রাখার মতো একটা table।

Namespace: নামের একটা বাক্স, যার নিজেরও নাম আছে

C-তে প্রতিটা function-এর নাম global, তাই দুইটা library-র দুজনেরই sort থাকতে পারে না। C library-গুলো এটা এড়ায় প্রতিটা নামের আগে একটা prefix বসিয়ে, যেমন sqlite3_open। C++-এর হাতে এর চেয়ে ভালো উপায় আছে। Namespace হলো নামের একটা বাক্স, যার নিজেরও একটা নাম আছে: দুইটা বাক্সে আলাদা আলাদা sort থাকতে পারে, আর তাদের মধ্যে কখনো ধাক্কা লাগে না।

Namespace বানানো, আর তার ভিতরে পৌঁছানো

namespace box_name {
    declarations: functions, variables, constants
}

box_name::name
  • namespace একটা বাক্স খোলে; box_name হলো বাক্সটার নিজের নাম।
  • দুই brace-এর মাঝে যা কিছু declare করা হয়, সবই থাকে বাক্সের ভিতরে।
  • ::, যার নাম scope operator, বাক্সের ভিতরে তাকায়: box_name::name মানে "ওই বাক্সের name"।

নিচের program-এ sort নামের দুইটা function, একটা দোকানের বাক্সে, আরেকটা স্কুলের বাক্সে।

#include <iostream>

namespace shop {
void sort()
{
    std::cout << "shop::sort puts prices cheapest first\n";
}
}

namespace school {
void sort()
{
    std::cout << "school::sort puts marks highest first\n";
}
}

int main()
{
    shop::sort();
    school::sort();
    return 0;
}
shop::sort puts prices cheapest first
school::sort puts marks highest first

Compiler কখনো জিজ্ঞেস করে না কোন sort-এর কথা বলছ, কারণ প্রতিটা call তার বাক্সের নাম বলে দেয়। main নিজে তোমার বানানো কোনো বাক্সে নেই। ও থাকে global namespace-এ, প্রতিটা program-এর সবচেয়ে বাইরের বাক্স, যেখানে C-র সব নামও থাকে।

Namespace মানে নামের বাক্স global namespace: main() আর তোমার বাকি বাইরের নামগুলো namespace shop void sort() call করো: shop::sort() namespace school void sort() call করো: school::sort() namespace std cout cin string sort max count left vector ... call করো: std::sort() তিনটা বাক্স, তিনটা sort, কোনো ধাক্কা নেই: প্রতিটা call তার বাক্সের নাম বলে using namespace std; দিলে std-এর সব নাম std:: ছাড়াই পাওয়া যায়

মানে namespace থাকলে দুই টুকরা code একই নাম ব্যবহার করতে পারে, আর box::name বলে দেয় তুমি কোনটা চাইছ।

std:: আর সেটা না লেখার তিনটা উপায়

C++-এর standard library তার প্রতিটা নাম রাখে একটাই namespace-এ, std। এজন্যই lesson 01 লিখেছিল std::cout: std বাক্সের cout। একটা program-এ পঞ্চাশবার std:: লেখা ক্লান্তিকর, তাই C++ এটা বাদ দেওয়ার তিনটা উপায় দেয়।

Using-declaration একটা নাম ভিতরে আনে: using std::cout;। Using-directive পুরো বাক্সটাই ভিতরে আনে: using namespace std;। দুইটাই কাজ করে যে লাইনে লেখা হয়েছে সেখান থেকে, যে block-এর ভিতরে আছে তার শেষ পর্যন্ত। File-এর একদম ওপরে লিখলে সেটা বাকি পুরো file; function-এর ভিতরে লিখলে শুধু ওই function।

#include <iostream>
#include <string>

using std::cout;

int main()
{
    using std::cin;

    std::string title;
    int pages = 0;
    cin >> title >> pages;
    cout << title << " has " << pages << " pages\n";
    return 0;
}
Matilda has 240 pages

এই output input Matilda 240-এর জন্য। Using-declaration-এর নিচে কোথাও cout-এর আগে std:: লাগে না, আর main-এর ভিতরে cin-এরও লাগে না। std::string-কে কখনো ভিতরে আনা হয়নি, তাই ওর std:: থেকে যায়।

তুমি লেখোকোথায়এরপর যা std:: ছাড়া লেখা যায়
std::coutপ্রতিটা ব্যবহারেকিছুই না; প্রতিবার বাক্সের নাম বলো
using std::cout;file-এর ওপরেcout, বাকি পুরো file-এ
using std::cin;একটা function-এর ভিতরেcin, শুধু ওই function-এর ভিতরে
using namespace std;file-এর ওপরেstd-এর সব নাম, বাকি পুরো file-এ

মানে এগুলোর যেকোনোটার পরে cout আসলে std::cout-ই। বদলায় শুধু এটুকু: বাক্স থেকে কয়টা নাম বের করে দিচ্ছ, আর কত দূর পর্যন্ত।

using namespace std-এর দাম, আর একটাই নিয়ম

Lesson 01 বলেছিল, using namespace std; তোমার program-এ শত শত নাম ঢেলে দেয়, আর তোমার কোনো একটা নামের সাথে ওদের কোনোটার ধাক্কা লাগতে পারে। এই হলো সেই ধাক্কা। Kenji-র আর কয়টা lap বাকি, সেটা ও রাখে left নামের একটা global variable-এ।

#include <iostream>

using namespace std;

int left = 3;

int main()
{
    cout << left << " laps left\n";
    return 0;
}

GCC 12 Playground-এর command line-এ আর -Wall -Wextra-এ একইভাবে এটা ফিরিয়ে দেয়: error: reference to 'left' is ambiguous। Note-গুলো দুই candidate-এর নাম বলে: Kenji-র 'int left' আর 'std::ios_base& std::left(ios_base&)'। std::left হলো <iostream>-এর একটা আসল নাম, এমন একটা setting যেটা output বাঁ দিক ঘেঁষে সাজায়। Kenji এটা কখনো চায়নি; using-directive এটাকে বাক্স থেকে বের করে দিয়েছে, আর এখন global left দুইটা।

Variable-টা main-এর ভিতরে সরিয়ে নাও, একই program compile হয়ে print করবে 3 laps left। Function-এর ভিতরে declare করা নাম বাইরের নামগুলোকে ঢেকে দেয়, বাক্স থেকে আসা নামও। তাই ধাক্কাটা লাগে file-এর একদম ওপরের নামগুলোতে, আর contest program ঠিক ওখানেই তার বড় array আর counter রাখে।

এই গেল এক file-এর দাম। Header-এ, মানে যে file অন্য file include করে, দামটা ছড়িয়ে পড়ে। #include header-এর লেখাটা হুবহু বসিয়ে দেয় যে file include করছে তার ভিতরে, C-র মতোই। তাই header-এর ভিতরের using-directive গিয়ে পড়ে ওই প্রতিটা file-এ। ওই file-গুলোর লেখক এই লাইন কখনো লেখেনি, তবু তাদের নামে ধাক্কা লাগা শুরু হয়।

তাই এই track-এর একটা নিয়ম আছে, আর একটা অভ্যাস। নিয়ম: using namespace std; কখনো header-এ যায় না। অভ্যাস: ছোট, এক file-এর contest program-এ এটা চলতে পারে, কিন্তু এই module, আর track-এর প্রতিটা project lesson, প্রতিটা standard নামের আগে std:: লেখে।

Header table: কোন file কোন নাম আনে

Namespace বলে একটা নাম কী নামে ডাকা হয়। Header বলে নামটা কোথায় declare করা, আর নামটা তোমার program-এ আসার আগে সেটা #include করতেই হবে। এই track-এর প্রতিটা নাম আসে নিচের কোনো একটা header থেকে। প্রথম কয়েকটা STL program লেখার সময় table-টা পাশে খুলে রাখার মতো।

Headerযা দেয়কোথায় শেখানো হয়
<iostream>std::cin, std::cout, std::cerrlesson 01 আর 02
<string>std::string, std::getline, std::to_stringModule 3
<sstream>std::istringstream, string-এর ভিতর থেকে সংখ্যা পড়াlesson 02-এ ইশারা, Module 3
<utility>std::pair, std::swap, std::movelesson 05 আর 06
<tuple>std::tuple, std::get, std::tielesson 06
<vector>std::vectorModule 2
<array>std::arrayModule 4
<deque>std::dequeModule 4
<list>std::listModule 5
<forward_list>std::forward_listModule 5
<stack>std::stackModule 6
<queue>std::queue, আর std::priority_queue-ওModule 6, Module 7
<set>std::set, std::multisetModule 8
<map>std::map, std::multimapModule 9
<unordered_set>std::unordered_setModule 10
<unordered_map>std::unordered_mapModule 10
<iterator>std::next, std::prev, std::distanceModule 11
<functional>std::greater, বড়টা আগে রাখার ক্রমModule 7, Module 12
<algorithm>std::sort, std::max, std::min, std::reverse, std::count, std::lower_boundlesson 05, Module 12, Module 13
<numeric>std::accumulate, std::iota, std::gcdModule 14
<bitset>std::bitsetModule 15
<chrono>program-এর সময় মাপার ঘড়িlesson 02 থেকে 04-এ মাপার কাজে লেগেছে

দুইটা row অনেককে অবাক করে। std::priority_queue-এর নিজের কোনো header নেই; ও থাকে <queue>-এ। আর std::swap আছে <utility>-এ, অথচ ওর পড়শি std::max আর std::min আছে <algorithm>-এ। তাই GCC যখন বলে কোনো নাম is not a member of 'std', আগে এখানে তার header খুঁজে দেখো।

যা ব্যবহার করো, ঠিক সেটাই include করো

Lesson 05 লেখার সময় একটা মজার জিনিস ধরা পড়েছিল। এই program-এ <algorithm> নেই, তবু GCC 12 এটা compile করে ফেলে।

#include <iostream>

int main()
{
    std::cout << std::max(3, 7) << '\n';
    return 0;
}
7

এটা চলছে কপাল জোরে। GCC-র library, libstdc++, <iostream> বানিয়েছে আরও কয়েকটা header জুড়ে জুড়ে। সেই শিকলের কয়েক file নিচে এটা <string> include করে, আর <string> include করে bits/stl_algobase.h, যে file-এ std::max define করা। Compiler Explorer-এর include list (GCC-র -H option) প্রতিটা ধাপ দেখায়।

অন্য compiler আসে অন্য library নিয়ে, আর সেগুলো অন্যভাবে বানানো। Compiler Explorer-এ আমরা তিনটা ছোট program compile করেছি, প্রতিটায় শুধু <iostream>, তিনটা toolchain-এ।

শুধু <iostream> রেখে call করা হলোGCC 12, libstdc++clang 15, libc++MSVC, Microsoft-এর library
std::maxcompile হয়compile হয়compile হয়
std::getlinecompile হয়compile হয়error C2039: 'getline': is not a member of 'std'
std::sorterror: 'sort' is not a member of 'std'; did you mean 'qsort'?compile হয়error C2039: 'sort': is not a member of 'std'

GCC column-টা Playground-এর command line, -O2 -std=c++17। Clang column হলো clang 15, -stdlib=libc++ দিয়ে, মানে clang-এর নিজের library, আর MSVC column হলো "x64 msvc v19.latest", /std:c++17 দিয়ে। প্রতিটা library সাথে আলাদা আলাদা বাড়তি জিনিস টেনে আনে, আর কেউই কথা দেয় না যে সামনেও আনবে। তাই যে program কোনো বাড়তির ওপর ভর দেয়, সেটা এক machine-এ ঠিক, পরেরটায় ভাঙা।

সমাধানের খরচ প্রতি header-এ এক লাইন। যে header-এর নাম ব্যবহার করছ, প্রতিটা include করো, program সেটা ছাড়া compile হলেও। তাহলে যেকোনো standard library-তে compile হবে, আজও, পরের library update-এর পরেও। তাই নিরাপদ উত্তর কখনো "আমার এখানে তো compile হলো" না, বরং "যে নামই ব্যবহার করি, তার header ওপরে আছে"।

bits/stdc++.h: সব header একসাথে, শুধু GCC-তে

<bits/stdc++.h> হলো GCC-র library-র ভিতরের একটা file, যেটা একবারে সব standard header include করে। File-টার নিজের comment একে বলে "an implementation file for a precompiled header", মানে GCC-র build দ্রুত করার একটা সহায়ক। এটা C++ standard-এর অংশ না। Contest programmer-রা এটা খুব পছন্দ করে, কারণ এক লাইনে এক ডজন লাইনের কাজ হয়, আর Playground সহ অনেক contest judge compile করে GCC দিয়ে।

#include <bits/stdc++.h>

int main()
{
    std::cout << "hello\n";
    return 0;
}
hello

এটা GCC 12-এর output। অন্য toolchain-এ file-টাই নেই। Compiler Explorer-এ clang 15, libc++ দিয়ে, মানে যে library একটা Mac নিজে থেকেই ব্যবহার করে, লাইন 1-এই থেমে যায়: fatal error: 'bits/stdc++.h' file not found। MSVC-ও ওখানেই থামে: fatal error C1083: Cannot open include file: 'bits/stdc++.h': No such file or directory। এটাই এই lesson-এর শুরুর Bob আর Maria-র গল্প।

Compile-এর সময়েও এর খরচ আছে, কারণ compiler প্রতিটা header পড়ে, লাগুক বা না লাগুক। আমরা hello program-টা দুইবার build করেছি, একবার <iostream> দিয়ে, একবার <bits/stdc++.h> দিয়ে, প্রতিটা একবার করে run।

কোথায়, আর কোন command<iostream> দিয়ে<bits/stdc++.h> দিয়ে
এই lesson-এর machine, GCC 14.2 (MinGW), g++ -std=c++17, ঘড়ি ধরে সময়1.39 s4.76 s
Compiler Explorer, GCC 12.2, -O2 -std=c++17, ওর দেখানো build time376 ms1130 ms
Compiler Explorer, GCC 12.2, preprocessor-এর পরে কয় লাইন (-E -P)22,38292,295

দুই machine-এই এই এক লাইন পাঁচ লাইনের একটা program-এর build অন্তত তিন গুণ ধীর করেছে। পরে Compiler Explorer-এ আরও তিনবার চালিয়ে এসেছে 289 থেকে 378 ms, বনাম 1,863 থেকে 2,888 ms। Local run-গুলো হয়েছে প্রতিটার একবার warm-up build-এর পরে, তাই তফাতটা disk-এর কারণে না। Contest-এ এই খরচ সহ্য করা যায়; শত শত file-এর project-এ প্রতিটা file এই দাম দেয়।

তাই track-এর নিয়ম সোজা। Contest program-এ <bits/stdc++.h> চলবে, আর যতবার আসবে, ততবার আমরা বলে দেব এটা শুধু GCC-র। Project lesson-এ এটা কখনো আসবে না, কারণ project-কে build হতে হয় team-এর ব্যবহার করা প্রতিটা compiler-এ।

Example 1: একই নাম, দুই বাক্সে

Namespace-এ variable-ও রাখা যায়। Alice একটা বইয়ের দোকান আর একটা library-র stock-এর হিসাব রাখে, আর দুইটা হিসাবের নামই stock।

#include <iostream>

namespace bookshop {
int stock = 0;
}

namespace library {
int stock = 0;
}

int main()
{
    bookshop::stock = 12;
    library::stock = 340;
    bookshop::stock = bookshop::stock - 2;

    std::cout << "bookshop " << bookshop::stock << ", library " << library::stock << '\n';
    return 0;
}
bookshop 10, library 340

দুইটা বই বিক্রি হওয়ায় বদলেছে শুধু দোকানের হিসাব। C-তে দুইটার আলাদা নাম লাগত, যেমন bookshop_stock আর library_stock; এখানে সেই কাজটা করে বাক্স।

Run in Compiler
Example 2: এক program-এ তিনটা sort

এবার দোকানের আর স্কুলের sort সত্যিকারের কাজ করে, আর দুইটাই দাঁড়িয়ে আছে তৃতীয় একটার ওপর, std::sort। এটা array-র একটা range ছোট থেকে বড় ক্রমে সাজায়, Module 12-এ শেখানো হবে। std::reverse একটা range উল্টে দেয়।

#include <algorithm>
#include <iostream>

namespace shop {
// Prices go cheapest first.
void sort(int prices[], int n)
{
    std::sort(prices, prices + n);
}
}

namespace school {
// Marks go highest first.
void sort(int marks[], int n)
{
    std::sort(marks, marks + n);
    std::reverse(marks, marks + n);
}
}

void print(const int a[], int n)
{
    for (int i = 0; i < n; i++) {
        if (i > 0) {
            std::cout << ' ';
        }
        std::cout << a[i];
    }
    std::cout << '\n';
}

int main()
{
    int prices[4] = {300, 120, 450, 200};
    int marks[4] = {72, 91, 65, 85};

    shop::sort(prices, 4);
    school::sort(marks, 4);
    print(prices, 4);
    print(marks, 4);
    return 0;
}
120 200 300 450
91 85 72 65

shop::sort-এর ভিতরে তাকাও। ওখানে সাধারণ sort(prices, prices + n) লিখলে সেটা খুঁজে পায় shop::sort-কেই, সবচেয়ে কাছের বাক্স। তখন GCC 12 বলে error: invalid conversion from 'int*' to 'int' [-fpermissive], সাথে একটা note, যেটা void shop::sort(int*, int)-এর নাম বলে। Call-টাকে standard library-তে পাঠায় std::।

Run in Compiler
Example 3: Amara-র দামের list, প্রতিটা header-এর নিজের কাজ আছে

Amara পড়ে তার দোকানের নাম আর n-টা দাম, তারপর print করে কয়টা জিনিস, মোট দাম, আর সবচেয়ে সস্তা ও সবচেয়ে দামি দামটা। একজন beginner আসলে এই program-টাই লেখে, ঠিক যে header-গুলো লাগে সেগুলো নিয়ে।

#include <algorithm>
#include <iostream>
#include <numeric>
#include <string>

const int MAX_N = 100;

int main()
{
    std::string shop;
    int n = 0;
    std::cin >> shop >> n;
    if (n == 0) {
        std::cout << shop << ": no items\n";
        return 0;
    }

    int prices[MAX_N] = {0};
    for (int i = 0; i < n; i++) {
        std::cin >> prices[i];
    }

    std::sort(prices, prices + n);
    long long total = std::accumulate(prices, prices + n, 0LL);

    std::cout << shop << ": " << n << " items, total " << total << '\n';
    std::cout << "cheapest " << prices[0] << ", dearest " << prices[n - 1] << '\n';
    return 0;
}
Bookworm: 4 items, total 1070
cheapest 120, dearest 450

এই output input Bookworm 4, তারপর 300 120 450 200-এর জন্য। প্রতিটা header নিজের দাম মেটায়: <algorithm> std::sort-এর জন্য, <iostream> std::cin আর std::cout-এর জন্য, <numeric> std::accumulate-এর জন্য, আর <string> std::string-এর জন্য। std::accumulate একটা range-এর যোগফল বের করে 0LL থেকে শুরু করে, তাই মোটটা হয় long long (Module 14)।

Zara প্রথমেই দিয়ে দেখেছে Bookworm 0। n == 0 check ছাড়া prices[n - 1] পড়ত prices[-1], array-র বাইরে; check থাকায় program print করে Bookworm: no items।

Run in Compiler

এটা কোথায় কাজে লাগে

  • SQLite। এর C interface-এর হাতে কোনো namespace নেই, তাই প্রতিটা public নাম শুরু হয় sqlite3_ দিয়ে, যেমন sqlite3_open আর sqlite3_exec। বাক্সের বদলে prefix, এটাই C-র উপায়।
  • LLVM। LLVM Coding Standards-এ একটা নিয়মের শিরোনামই "Do Not Use 'using namespace std'"। ওরা স্পষ্ট করে std:: লেখা পছন্দ করে, আর বলে header-এ using-directive থাকলে যে file সেটা include করে, তার প্রতিটা নোংরা হয়।
  • Chromium। Google-এর এই browser মেনে চলে Google C++ Style Guide, যেটা বলে using namespace foo-এর মতো using-directive ব্যবহার না করতে।
  • GCC-র নিজের library। bits/stdc++.h আসে libstdc++-এর সাথে, আর এর comment নিজেকে বলে precompiled header-এর একটা implementation file। এজন্যই এটা আছে GCC-তে আর GCC ব্যবহার করা judge-গুলোতে, আর কোথাও না।

যে ভুলগুলো সবাই করে

১. Using লাইন ছাড়াই std:: বাদ দেওয়া।

cout << "hello\n";

প্রতিটা command line-এ error: error: 'cout' was not declared in this scope; did you mean 'std::cout'?। GCC বাক্সের নামটাও বলে দেয়। লেখো std::cout। এই ভুলটা তুমি করবে, কারণ online-এ পাওয়া বেশিরভাগ code শুরু হয় using namespace std; দিয়ে, আর তুমি ওই লাইন বাদ দিয়ে শুধু ভিতরের অংশটা copy করো।

২. দুইটা colon-এর জায়গায় একটা।

std:cout << "hello\n";

Playground-এর command line ভুল 1-এর বার্তাটাই দেয়। -Wall -Wextra-এ GCC 12 সূত্রটা যোগ করে: warning: label 'std' defined but not used [-Wunused-label]। এক colon-এর std: হলো C-র label, goto-র একটা গন্তব্য, তাই cout খালি পড়ে থাকে। তাড়াহুড়োয় টাইপ করলে এটা হবে, কারণ দুই colon মানে একই key দুইবার চাপা।

৩. Header ছাড়া নাম ব্যবহার করা।

#include <iostream>

int main()
{
    std::vector<int> v(3);
    return 0;
}

প্রতিটা command line-এ error: error: 'vector' is not a member of 'std', সাথে কাজের একটা note, 'std::vector' is defined in header '<vector>'; did you forget to '#include <vector>'?। তবে GCC সবসময় header চেনে না: std::sort-এর বেলায় ও প্রস্তাব দেয় 'qsort', আর std::accumulate-এর বেলায় কিছুই না। তাই "is not a member of 'std'" পড়ো "একটা header নেই" হিসেবে, আর নামটা table-এ খুঁজে দেখো।

৪. নিজের function-কে তার বাক্স ছাড়া call করা।

namespace shop {
void sort()
{
}
}

sort();

প্রতিটা command line-এ error: error: 'sort' was not declared in this scope; did you mean 'shop::sort'?। বাক্সের বাইরে থেকে এর নামগুলোর আগে বাক্সের নাম লাগে। লেখো shop::sort();। এটা ভুলে যাবে, কারণ shop-এর ভিতরে সাধারণ নামেই কাজ হচ্ছিল।

মাথা খাটাও

Bob বড়জোর 100টা mark পড়ে, সাজায়, তারপর print করে কয়টা ছিল আর সবচেয়ে কমটা কত। গোনার হিসাবটা ও রাখে একটা global variable-এ, C-তে যেভাবে রাখত।

#include <algorithm>
#include <iostream>

using namespace std;

int count = 0;

int main()
{
    int marks[100] = {0};
    int x = 0;
    while (count < 100 && cin >> x) {
        marks[count] = x;
        count++;
    }
    sort(marks, marks + count);
    cout << count << " marks, lowest " << marks[0] << '\n';
    return 0;
}

GCC 12 এটা মানে না, যে লাইনেই count আছে সেখানেই আটকায়, অথচ Bob library-র কাছে count নামের কিছুই চায়নি। GCC 12 কী বলে, আর কেন? তারপর দুইটা আলাদা সমাধান খুঁজে বের করো, যার প্রতিটায় variable-এর নাম count-ই থাকবে, আর using namespace std; লাইনটাও থাকবে।

Header table-এর <algorithm> row আবার পড়ো: ওখানে sort একা নেই। তারপর মনে করো, using-directive যে নাম বাক্স থেকে বের করে দেয়, কোন ধরনের variable সেটাকে ঢেকে দিতে পারে, আর কোনটা পারে না।

অনুশীলন ১সহজ

Zara ক্লাসের জন্য বানানের একটা list বানায়, আর শব্দগুলো চায় অভিধানের ক্রমে। Program-টা লেখো ঠিক যে header-গুলো লাগে সেগুলো দিয়ে: অদরকারি কোনো header না, কোনোটা বাদও না, আর <bits/stdc++.h> তো একদমই না।

Input. একটা লাইনে n, তারপর n-টা শব্দ।

Output. n-টা শব্দ অভিধানের ক্রমে, প্রতি লাইনে একটা।

Constraints. 1 <= n <= 100। প্রতিটা শব্দ 1 থেকে 20টা ছোট হাতের অক্ষরের।

Sample. Input 4, তারপর pear apple zebra mango দিলে চার লাইনে আসে apple, mango, pear আর zebra।

#include <iostream>
// Add the other headers this program uses here, one per line,
// in alphabetical order. Not <bits/stdc++.h>.

const int MAX_N = 100;

int main()
{
    int n = 0;
    std::cin >> n;

    // Read n words into an array of std::string, sort it with
    // std::sort, and print the words one per line.

    return 0;
}

আলাদা করে গ্রেড হয় না। Playground-এ একটা header বাদ থাকলেও এটা compile হয়ে যেতে পারে, আর এই lesson-এর কথাটাই সেটা, তাই প্রতিটা std:: নাম table-এর সাথে মিলিয়ে নাও।

Run in Compiler
অনুশীলন ২মাঝারি

Zara-র আবহাওয়া station চায় দুইটা reading-এর মধ্যে জোরালোটা: যেটা শূন্য থেকে বেশি দূরে, তাই -7 হারিয়ে দেয় 5-কে। std::max এটা বোঝায় না, তাই ও নিজের একটা max লেখে, নিজের একটা বাক্সে, weather, আর তুলনার জন্য দুইটা উত্তরই print করে।

Input. দুইটা পূর্ণসংখ্যা a আর b।

Output. দুইটা লাইন: প্রথমে std::max, একটা space আর দুইটার বড়টা; তারপর weather::max, একটা space আর যেটা শূন্য থেকে বেশি দূরে। দুইটাই শূন্য থেকে সমান দূরে হলে weather::max দেয় a।

Constraints. প্রতিটা পূর্ণসংখ্যা -100 থেকে 100-এর মধ্যে।

Sample. Input -7 5 দিলে দুই লাইনে আসে std::max 5 আর weather::max -7।

#include <algorithm>
#include <iostream>

namespace weather {
// Return whichever of a and b is further from zero; on a tie, return a.
int max(int a, int b)
{
    return a; // replace this line
}
}

int main()
{
    int a = 0;
    int b = 0;
    std::cin >> a >> b;

    // Print "std::max " and std::max(a, b) on one line,
    // then "weather::max " and weather::max(a, b) on the next.

    return 0;
}

আলাদা করে গ্রেড হয় না। Sample-এর আগে Zara দিয়ে দেখবে 5 -5 আর 0 0।

Run in Compiler

সচরাচর যে প্রশ্নগুলো আসে

  • using namespace std; কি আমার program বড় বা ধীর করে?

    না। এটা শুধু বদলায়, তোমার code পড়ার সময় compiler কোন নামগুলো খুঁজে পায়। যে program তৈরি হয়, সেটা সব জায়গায় std:: লিখলে যা হতো, হুবহু তাই।

  • <bits/stdc++.h> কি program চলার সময় ধীর করে?

    না, শুধু compile ধীর করে। যে declaration কেউ ব্যবহার করে না, তা থেকে কোনো machine code তৈরি হয় না। এই lesson-এর machine-এ GCC 14.2 (MinGW) দিয়ে build করা দুইটা hello program-এর size এসেছে 65,052 আর 65,241 byte।

  • std::cout-এ দুইটা colon, অথচ std::cin.tie-তে একটা dot কেন?

    :: তাকায় একটা namespace-এর ভিতরে, মানে নামের বাক্সে। . পৌঁছায় একটা object-এর member-এ, ঠিক C-র struct-এর মতো। std::cin হলো std বাক্সের একটা object, আর tie তার একটা member।

  • আমি কি std-এ নিজের function যোগ করতে পারি?

    না। C++ standard বলে, namespace std-এ নিজের declaration যোগ করা undefined behaviour, হাতে গোনা কয়েকটা ক্ষেত্র ছাড়া। নিজের নাম রাখো নিজের বাক্সে, যেমন shop আর weather রাখে।

  • Bob জিজ্ঞেস করে: scanf আর printf কি এখনো ব্যবহার করা যায়?

    যায়। C++-এ এরা আসে <cstdio> থেকে, যেটা stdio.h-এর C++ রূপ, std::scanf আর std::printf নামে। Lesson 02-এর নিয়ম তবু খাটে: এক program-এ input আর output-এর একটাই পরিবার।

মূল কথা

  • Namespace হলো নামের একটা বাক্স, যার নিজেরও নাম আছে; box::name তার ভিতরে পৌঁছায়, তাই shop::sort আর school::sort-এ কখনো ধাক্কা লাগে না।
  • পুরো standard library থাকে std-এ; using std::cout; একটা নাম বের করে দেয়, using namespace std; দেয় সবগুলো।
  • using namespace std; ছোট contest file-এ চলে, header-এ কখনো না; এই module প্রতিটা standard নামের আগে std:: লেখে।
  • প্রতিটা standard নাম আসে table-এর কোনো একটা header থেকে; যেটাই ব্যবহার করো, include করো, কারণ কোন header কী টেনে আনে, সেটা library ভেদে আলাদা।
  • <bits/stdc++.h> GCC-র নিজের file: libc++ সহ clang আর MSVC এটা মানে না, আর এটা একটা hello program-এর build অন্তত তিন গুণ ধীর করেছে।

এটাই এই module-এর শেষ lesson। এরপর আসছে এর problem set, দশটা judged problem, যেগুলোতে লাগবে lesson 01 থেকে 07, আর তারপর Module 2 খুলবে std::vector।

lesson ৭ শেষ

শেষ হলে চিহ্ন দিন, অগ্রগতি আপনার সাথে থাকবে।

পরেরটা: Problem: যতটুকু C++ দরকার

std::, namespace আর যে header-গুলো সত্যিই include করবে | Learn C++ STL | Progsity