0
0

独習C++ 4章

Last updated at Posted at 2024-08-26

4.3.3 グローバル変数とstatic変数

グローバル変数は、main()関数が始まる前から存在し、main関数が終了した後に破棄される。

#include <iostream>

class A
{
public:
   A();
   ~A();
};

A::A(){
   std::cout << "consuructor" << std::endl;
}

A::~A()
{
   std::cout << "desstructor" << std::endl;
}

// Before main() is called, this constructor is called.
// After main() finishes, this destructor is called.
A a;

int main(){
   std::cout << "main() function" << std::endl;
}
  • static変数

ローカル変数をstatic変数にすると、スコープから抜けても破棄されず
プログラムが終了するまで残る。
グローバル変数をstaticにすると、ファイルスコープなグローバル変数になる。

#include <iostream>

int count(){
   // static変数になっているローカル変数は、寿命が長い以外は、一緒なので、有効スコープからしか
   // アクセスできない。
   static int counter = 0;
   return ++counter;
}

int main(){
   std::cout << "1回目: " << count() << std::endl;

   std::cout << "2回目: " << count() << std::endl;

   std::cout << "3回目: " << count() << std::endl; 
}


1回目: 1
2回目: 2
3回目: 3

4.3.4 ダングリングポインター

#include <iostream>

int* dangling_pointer(){
   int i = 0;
   return &i;
}

int main(){
   int*p = dangling_pointer();
   // 寿命が尽きたローカル変数を変更しようとしている。
   *p = 42;
}

4.4 初期化構文付き条件分岐

4.4.1 初期化構文付きif文

#include <iostream>

int foo(int value){
   std::cout << "foo " << value << std::endl;
   return value;
}

bool is_even(int value){
   return value%2 == 0;
}

bool is_zero(int value){
   return value == 0;
}

int main(){
   if(int result = foo(42); is_even(result) && !is_zero(result)){
      std::cout << "foo(42)は0ではない偶数を返しました" << std::endl;
   }
}

4.5 分割コンパイル

4.5.1 コンパイル

ソースファイルを実行形式ファイルに変換する手順をコンパイルという。

4.5.2 プリプロセス

→コンパイルの直前に行われる、ヘッダーファイルを読み込んだり、マクロの展開をしたり。

4.5.3 リンクとビルド

ビルド: 複数のソースファイルから1つのプログラムを作り上げる手順のこと。

リンク: オブジェクトファイルを結合すること。

  • Main.cpp
# include "test2.hpp"

int main(){
    show_value(42);
}
  • Test2.hpp
void show_value(int value);
  • Test2.cpp
#include "test2.hpp"

#include <iostream>

void show_value(int value){
   std::cout << "value=" << value << std::endl;
}

4.5.4 extern変数

ヘッダーファイルや複数のソーづファイルでグローバル変数を
宣言してしまうと、それぞれのソースファイルがコンパイルされた時に
それぞれのオブジェクトファイルがグローバル変数の実態を持ってしまう
原因: 変数宣言が暗黙のうちに変数定義まで含んでいる

変数宣言の際に、Externキーワードを使うとそのグローバル変数の実体はどこか
別のところで定義されてるものとして扱う。
→extern変数

  • ただしこれはグローバルスコープの変数でしか宣言できない。

  • Test2.cpp

# include <iostream>

int value = 42;

void show_extern_variable(){
    std::cout << "extern varibale's address: " << &value << std::endl; 
    std::cout << "extern varibale's value: " << value << std::endl; 
}
  • Main.cpp
# include <iostream>

extern int value;

void show_extern_variable();

int main(){
    std::cout << "main: extern変数のアドレス" << &value << std::endl;
    std::cout << "main: extern変数の値" << value << std::endl;

    value = 0;

    show_extern_variable();
}

4.5.5 staticメンバー変数の定義

Staticメンバー変数だけは、クラス定義時だけの宣言では不十分で、
クラスの定義の外側で別途定義が必要だった。
定義をヘッダーファイルに書いちゃうと、複数のファイルで実体が発生しちゃうから
どこか一つのソースファイルでのみ定義する必要がある。

4.6 インライン関数

4.6.1 ヘッダーファイルに定義された関数のインライン展開

ヘッダーに関数定義を書くことができれば、コンパイラはその関数本体を呼び出しもとにインライン展開する。

4.6.2 インライン指定

ヘッダーファイルに関数の宣言と定義を両方行うために必要。
あるヘッダーファイルが、複数のソースファイルにインクルードされている場合、そのヘッダーファイルにODR(単一定義規則)というルールに違反する。インライン指定を行うとこの問題を解決してくれるようコンパイラーが調整してくれる。

4.6.3 自動インライン化

クラスの定義時にメンバー関数を宣言と同時に定義すると、それは自動的にインライン関数となるのでODRに反しない。

#include <iostream>

class A
{
    int i;

public:
    A() : i(0) {};

    void set_i(int i)
    {
        this->i = i;
    }

    void show() const
    {
        std::cout << i << std::endl;
    }
};

int main(){
    A a;
    a.show();
    a.set_i(123);
    a.show();
}

↑これは自動的にインライン化される。

  • intとかの変数は?

int などの組み込み型の宣言は自動的に定義されます。これは、コンパイラが割り当てられる領域の量を認識するためです。

4.6.4 宣言のみのメンバー関数をinlineにする

クラス定義でメンバー関数の宣言はしたものの、定義までは行わない場合、そのメンバー関数は自動でインライン化されない

#include <iostream>

class A{
    int i;

    public:
    // コンストラクターをインライン指定付きで宣言
    inline A();

    // 自動でインラインになるメンバー関数
    void set_i(int i){
        this->i = i;
    };

    // インラインにならないメンバー関数
    void show() const;
};

A::A():i(0){}

void A::show() const {
    std::cout << i << std::endl;
}

int main(){
    A a;
    a.show();
    a.set_i(123);
    a.show();
}

4.7 名前空間

4.7.1 名前空間とスコープ解決演算子

#include <iostream>

namespace A{
    struct A{
        int a;
    };

    void foo(){
        std::cout << "A::foo()" << std::endl;
    }
}

namespace B{
    struct S{
        int b;
    };

    void foo(){
        std::cout << "B::foo()" << std::endl;
    }
}

int main(){
    A::foo();

    B::foo();

    A::A as;
    B::S bs;
}

4.7.2 ネストした名前空間


namespace library{
    namespace module{
        namespace detail{
            void internal_function();
        }
    }
}

namespace library::module::detail

4.7.3 名前空間の省略

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0