ムーブ代入演算子

前回、オブジェクトの初期化で右辺値を指定し、ムーブコンストラクタが実行された。
オブジェクトの代入で右辺値を指定された場合は、ムーブ代入演算子が実行される。

右辺値参照・ムーブセマンティクス - cpprefjp C++日本語リファレンス

profile.hで、

このように"="を演算子オーバーロードする。

profile.cppでは、

メンバが残っていたら破棄して、ポインタを挿げ替えて、渡された方にはnullptrをセット。

main.cppでは、

std::move経由で代入。

$ vi main.cpp 
$ g++ -o main main.cpp profile.cpp -std=c++11
$ ./main 
constructor
set_profile
get_name
obj1.get_name() = Taro
get_age
obj1.get_age() = 20
get_address
obj1.get_address() = Tokyo
copy_constructor
get_name
obj2.get_name() = Taro
get_age
obj2.get_age() = 20
get_address
obj2.get_address() = Tokyo
constructor
set_profile
get_name
obj3.get_name() = Jiro
get_age
obj3.get_age() = 18
get_address
obj3.get_address() = Osaka
set_profile
copy_assignment_operator
get_name
obj3.get_name() = Taro
get_age
obj3.get_age() = 20
get_address
obj3.get_address() = Tokyo
constructor
set_profile
get_name
obj4.get_name() = Saburo
get_age
obj4.get_age() = 16
get_address
obj4.get_address() = Nagoya
move_assignment_operator
get_name
obj4.get_name() = Taro
get_age
obj4.get_age() = 20
get_address
obj4.get_address() = Tokyo
before delete [] name_ = 0x1d4a0f0
before age_ = 20
before delete [] address_ = 0x1d4a110
destructor
name_ = nullptr
age_ = 0
address_ = nullptr
destructor
before delete [] name_ = 0x1d4a070
before age_ = 20
before delete [] address_ = 0x1d4a090
destructor
before delete [] name_ = 0x1d4a030
before age_ = 20
before delete [] address_ = 0x1d4a050
destructor
$

こうなる。

Sample/cpp/move_assignment_operator/move_assignment_operator/src/move_assignment_operator at master · bg1bgst333/Sample · GitHub

ムーブコンストラクタ

引数に右辺値参照を取るコンストラクタ「ムーブコンストラクタ」を定義できる。

右辺値参照・ムーブセマンティクス - cpprefjp C++日本語リファレンス

profile.hに、

こんな感じでムーブコンストラクタを宣言。

profile.cppは、

引数のobjのメンバのポインタに挿げ替え。

main.cppでは、

std::move経由で右辺値として渡す。

$ vi main.cpp 
$ g++ -o main main.cpp profile.cpp --std=c++11
$ ./main 
constructor
set_profile
get_name
obj1.get_name() = Taro
get_age
obj1.get_age() = 20
get_address
obj1.get_address() = Tokyo
copy_constructor
get_name
obj2.get_name() = Taro
get_age
obj2.get_age() = 20
get_address
obj2.get_address() = Tokyo
move_constructor
get_name
obj3.get_name() = Taro
get_age
obj3.get_age() = 20
get_address
obj3.get_address() = Tokyo
before delete [] name_ = 0x2506070
before age_ = 20
before delete [] address_ = 0x2506090
destructor
name_ = nullptr
age_ = 0
address_ = nullptr
destructor
before delete [] name_ = 0x2506030
before age_ = 20
before delete [] address_ = 0x2506050
destructor
$

obj2はすでにnullptrになっている。

Sample/cpp/move_constructor/move_constructor/src/move_constructor at master · bg1bgst333/Sample · GitHub

nullptr

C++11からは、ポインタへのNULLのセットは、nullptrを使うことが推奨されている。

nullptr - cpprefjp C++日本語リファレンス

nullptr.cppで、

intとconst char *を引数とするfuncがある。

値、指定された文字列をそれぞれ出力するだけ。

  // 0とNULLの場合.
  func(0); // 0を出力.
  func(NULL); // NULLを出力.(この環境では, 呼び出しが曖昧ということでコンパイルエラーになった.)
  func(nullptr); // C++11ではnullptrを推奨.

こうすると、

$ vi nullptr.cpp 
$ g++ nullptr.cpp -o nullptr -std=c++11
nullptr.cpp: 関数 ‘int main()’ 内:
nullptr.cpp:20:12: エラー: オーバーロードされている ‘func(NULL)’ の呼び出しが曖昧です
   func(NULL); // NULLを出力.(この環境では, 呼び出しが曖昧ということでコンパイルエラーになった.)
            ^
nullptr.cpp:5:6: 備考: candidate: void func(int)
 void func(int val); // オーバーロード関数func(int val)
      ^~~~
nullptr.cpp:6:6: 備考: candidate: void func(const char*)
 void func(const char *ptr); // オーバーロード関数func(const char *ptr)
      ^~~~
$ 

このように曖昧なのでコンパイルエラー。

こうすると、

$ vi nullptr.cpp 
$ g++ nullptr.cpp -o nullptr -std=c++11
$ ./nullptr 
val = 10
ptr = ABC

だったり、

val = 0
ptr = $

だったり、コンパイルして実行できる。

Sample/cpp/nullptr/nullptr/src/nullptr at master · bg1bgst333/Sample · GitHub

ioctl

ioctlは、デバイスを制御するのに使う。

Man page of IOCTL

今回は、ネットワークデバイスであるNICからIPを取得する。

ioctl.cで、

インターフェース名を入力。
ioctlでSIOCGIFADDRを送る。
成功するとstruct ifreq型のsifrに情報が格納される。

$ ifconfig
enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255
        inet6 fe80::3b07:5151:e763:f8b0  prefixlen 64  scopeid 0x20<link>
        ether 08:00:27:75:6b:bc  txqueuelen 1000  (Ethernet)
        RX packets 60323  bytes 13211145 (12.5 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 60397  bytes 8129752 (7.7 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1  (Local Loopback)
        RX packets 20  bytes 1720 (1.6 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 20  bytes 1720 (1.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

$ vi ioctl.c 
$ gcc ioctl.c -o ioctl
$ ./ioctl 
interface_name: enp0s3
enp0s3 ip address = 10.0.2.15
$

IPが出力された。

Sample/unixsyscall/ioctl/ioctl/src/ioctl at master · bg1bgst333/Sample · GitHub

msync

msyncでメモリマップの内容に合わせてファイルを同期する。

Man page of MSYNC

msync.cで、

"test.txt"を開いたら、内容を"VWXYZ"に書き換えて、msyncで同期する。

$ ls
msync  msync.c  test.txt
$ vi msync.c 
$ gcc msync.c -o msync
$ vi test.txt 
$ cat test.txt 
ABCDE
$ ./msync 
sst.st_size = 6
page_size = 4096
memory_map_size = 4096
$ cat test.txt 
VWXYZ
$

"ABCDE"が"VWXYZ"に書き換えられた。

Sample/unixsyscall/msync/msync/src/msync at master · bg1bgst333/Sample · GitHub

mmap

mmapは、ファイルの内容をメモリにマッピングすることで高速にアクセスできる。

Man page of MMAP

mmap.cで、

ファイルサイズを取得し、メモリのページサイズも取得し、メモリマップサイズを計算。
"test.txt"を開いて、メモリにマッピング
メモリマップの中身を出力したら、アンマップして閉じる。

$ ls
mmap  mmap.c  test.txt
$ cat test.txt 
ABCDE
$ vi mmap.c 
$ gcc mmap.c -o mmap
$ ./mmap 
sst.st_size = 6
page_size = 4096
memory_map_size = 4096
-----begin-----
ABCDE

-----end-----
$

メモリ上にマッピングされた。

Sample/unixsyscall/mmap/mmap/src/mmap at master · bg1bgst333/Sample · GitHub

isatty

isattyは、ファイルディスクリプタが端末を参照しているかどうかを返す。

Man page of ISATTY

わかりにくいので補足すると、ファイルディスクリプタの出力先が標準出力であれば、端末は参照されていると言えるし、
リダイレクトなどで、ファイルなどに出力される場合は参照されていない。

isatty.cで、

isattyが1なら、標準出力、0なら、リダイレクトという形で判定できる。

$ vi isatty.c 
$ gcc isatty.c -o isatty
$ ./isatty 
ABCDE
ABCDE
ABCDE
ABCDE
ABCDE
$ ./isatty > test.txt
$ cat test.txt 
-----header-----
ABCDE
ABCDE
ABCDE
ABCDE
ABCDE
-----footer-----
$

リダイレクトの場合は、headerとfooterが付いているので、ちゃんと判定できてる。

Sample/unixsyscall/isatty/isatty/src/isatty at master · bg1bgst333/Sample · GitHub