LIFE LOG(ここにはあなたのブログ名)

あつあつ備忘録

ソフトやハード、時にはメカの備忘録をまとめていきます

【Ubuntu18.04】CUDAインストール時のエラー「E: 問題を解決することができません。壊れた変更禁止パッケージがあります。」

f:id:AtsuyaKoike:20190822190652j:plain:w400

画像元:CUDA Toolkit | NVIDIA Developer

最初に

Ubuntu18.04でCUDAをインストールしようとしたら、以下のエラーがでたため解決方法をメモします。

構成

  • エラー内容
  • NVIDIAドライバのアンインストール
  • NVIDIAドライバ、CUDA、cuDNNのインストール

エラー内容

$ sudo apt-get install cuda-runtime-10-1 
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
インストールすることができないパッケージがありました。おそらく、あり得
ない状況を要求したか、(不安定版ディストリビューションを使用しているの
であれば) 必要なパッケージがまだ作成されていなかったり Incoming から移
動されていないことが考えられます。
以下の情報がこの問題を解決するために役立つかもしれません:

以下のパッケージには満たせない依存関係があります:
 cuda-runtime-10-1 : 依存: cuda-drivers (>= 418.67) しかし、インストールされようとしていません
E: 問題を解決することができません。壊れた変更禁止パッケージがあります。

これはNVIDIAドライバをインストール時にNouveauを無効化していないと場合に出てくるエラーです。 そのため、一度NVIDIAドライバをインストールし直すことで解決できます。

NVIDIAドライバのアインインストール

$ dpkg -l | grep nvidia
$ dpkg -l | grep cuda

最初にこのコマンドでインストールされているかの確認をします。

$ sudo apt-get --purge remove nvidia-*
$ sudo apt-get --purge remove cuda-*

そしてアンインストールをします。 再度grepをかけてすべてアンインストールできているかの確認をします。できていない場合はシンボルマークを使用せずアンインストールしてください。

NVIDIAドライバ、CUDA、cuDNNのインストール

以下のページに示したようにNVIDIAドライバ、CUDA、必要あればcuDNNをインストールしてください。 atsuyakoike.hatenablog.com

【Ubuntu18.04】rviz_visual_toolsのインストール

f:id:AtsuyaKoike:20190421152613p:plain

catkin_make中にエラーがでたので調べたのですが、情報が少なかったのでメモ

インストール方法

$ sudo apt-get install ros-melodic-rviz-visual-tools

インストールしていないこと出るエラー

Could not find a package configuration file provided by "rviz_visual_tools"
  with any of the following names:

    rviz_visual_toolsConfig.cmake
    rviz_visual_tools-config.cmake

  Add the installation prefix of "rviz_visual_tools" to CMAKE_PREFIX_PATH or
  set "rviz_visual_tools_DIR" to a directory containing one of the above
  files.  If "rviz_visual_tools" provides a separate development package or
  SDK, be sure it has been installed.

エラー部分をピックアップするとこんな感じです。

【Ubuntu18.04】NVIDIAドライバ・CUDA・cuDNNのインストール方法

はじめに

Ubuntu18.04でNVIDIA周りの環境構築の方法を記述します。 Ubuntu16.04よりも少し面倒くさいですが、手順を追えば難しいことはありません。

想定している環境

Ubuntu18.04にインストールするもの

  • NVIDIAドライバ 430.26
  • Cuda 10.0
  • cuDNN v7.6.1

NVIDIAドライバのインストール

ディスプレイマネージャを変更する

変更したほうが簡単なのでデフォルトのgdm3からlightdmに変更します。

$ sudo apt-get install lightdm

このコマンドをうつと、デフォルトのディスプレイマネージャをgdm3とlightdmのどちらかにするか聞かれるので、lightdmを選択してください。 そして再起動してディスプレイマネージャが変更されていることを確認します。(ログイン画面が変更されていれば問題ありません)

$ reboot

Nouveauを無効化する

もう一度再起動してください。 Ubuntuが立ち上がるときEscキーを連打してください。 そしたら以下のような画面になります。

f:id:AtsuyaKoike:20190808115841j:plain:w600

ここで、Ubuntuにカーソルがある状態で、キーボードのEを押してください。すると次のような画面になります。

f:id:AtsuyaKoike:20190808120012j:plain:w600

そしたら下から2行目に注目してください。

quiet splash $vt_handoff

という記述があると思います。これを以下のように変更します。

quiet splash nomodeset $vt_handoff

そしたらF10を押してください。 続いて、Ctrl+Alt+F1でCLIモードにします。(F1でだめだったらF2, F3・・・と試してください) CLIモードでログインをし、以下を内容を行ってください。

ディスプレイマネージャをストップする

以下のコマンドでディスプレイマネージャをストップします。

$ sudo service lightdm stop

NVIDIAドライバのインストール

$ sudo apt-get install nvidia-384
$ reboot

インストールできたかの確認

$ nvidia-smi 
Thu Aug  8 21:15:46 2019       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.116                Driver Version: 390.116                   |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 1060    Off  | 00000000:01:00.0  On |                  N/A |
| N/A   50C    P0    28W /  N/A |    176MiB /  6070MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0       960      G   /usr/lib/xorg/Xorg                           104MiB |
|    0      1470      G   /usr/bin/gnome-shell                          69MiB |
+-----------------------------------------------------------------------------+

以上でNVIDIAドライバのインストールは終わりです。

CUDAのインストール

こちらからインストーラのダウンロードをします。

developer.nvidia.com

続いて以下のコマンドを入力

$ sudo dpkg -i cuda-repo-ubuntu1804_10.0.130-1_amd64.deb
$ sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub
$ sudo apt-get update
$ sudo apt-get install cuda-10-0

bashrcに追記

$ vi ~/.bashrc

以下の内容を追記します。

export PATH=/usr/local/cuda-10./bin:${PATH}
export LD_LIBRARY_PATH=/usr/local/cuda-10.0/lib64:${LD_LIBRARY_PATH}

そして一度再起動します。。

$ reboot

パスの確認

$ echo $PATH             # 出力に"/usr/local/cuda-10.0/0bin"が含まれているか?
$ echo $LD_LIBRARY_PATH  # 出力に"/usr/local/cuda-10.0/lib64"が含まれているか?
$ which nvcc             # 出力が"/usr/local/cuda-10.0/bin/nvcc"になっているか?
$ nvidia-smi             # nvidiaのGPUの情報が表示されているか? CUDAのバージョンは10.1になっている可能性があるが問題ない

これでCUDAのインストールは終了です。

cuDNNのインストール

ダウンロード

こちらからcuDNNのインストーラをダウンロードします。ただし、NVIDIA Developerのアカウントが無い場合は作成する必要があります。

developer.nvidia.com

Download cuDNN v7.6.1 (June 24, 2019), for CUDA 10.0の

  • cuDNN Runtime Library for Ubuntu18.04 (Deb)
  • cuDNN Developer Library for Ubuntu18.04 (Deb)
  • cuDNN Code Samples and User Guide for Ubuntu18.04 (Deb)

をダウンロードします。

インストール

そしてインストールします。

$ sudo dpkg -i libcudnn7_7.6.1.34-1+cuda10.0_amd64.deb 
$ sudo dpkg -i libcudnn7-dev_7.6.1.34-1+cuda10.0_amd64.deb
$ sudo dpkg -i libcudnn7-doc_7.6.1.34-1+cuda10.0_amd64.deb

動作確認

$ cuda-install-samples-10.0.sh ~/
$ cd ~/NVIDIA_CUDA-10.0_Samples/
$ make -j8
$ cd 2_Graphics/Mandelbrot/
$ ./Mandelbrot 

f:id:AtsuyaKoike:20190808214443p:plain

この画面を出すことができれば環境構築終了です。

ディスプレイマネージャをgdm3に戻す(任意)

以下のコマンドで戻すことができます。

$ sudo dpkg-reconfigure gdm3

お疲れ様でした。

メモ

$ nvidia-smi
Thu Aug  8 21:53:18 2019       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 430.26       Driver Version: 430.26       CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 1060    Off  | 00000000:01:00.0  On |                  N/A |
| N/A   51C    P0    28W /  N/A |    227MiB /  6070MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0      1230      G   /usr/lib/xorg/Xorg                            18MiB |
|    0      1303      G   /usr/bin/gnome-shell                          48MiB |
|    0      1553      G   /usr/lib/xorg/Xorg                            86MiB |
|    0      1705      G   /usr/bin/gnome-shell                          71MiB |
+-----------------------------------------------------------------------------+

Ubuntu18.04のインストール

ノートPCにUbuntu18.04のインストール方法を紹介します。 今回はHDDとSSDの2つが載ったPCにインストールをします。

構築する環境

概要
インストールPC ALIENWARE 15 R3
インストールするOS Ubuntu18.04 LTS
スワップ領域 約16GB
インストール先 SSD

f:id:AtsuyaKoike:20190807164201j:plain:w500
まずPCからHDDを取り外します。その手順は以下のとおりです。

  1. ネジを外す
  2. カバーを外す
  3. HDDを取り外す

f:id:AtsuyaKoike:20190807194728j:plain:w500
HDDを外すとこのようになります。

そしたら、PCにライブUSBを接続します。(ライブUSBの作成の仕方は後で記事にします) BIOS画面を立ち上げ、セキュアブートをオフにし、BootOptionでライブUSBのプライオリティをトップにします。

f:id:AtsuyaKoike:20190807195348j:plain:w500
画面が立ち上がったら言語を日本語に変更し、

  1. Ubuntuをインストールを選択
  2. キーボードレイアウトは左右とも「日本語」を選択
  3. ネットワークにはまだ接続しないので、ここでは設定しない
  4. 通常のインストール、グラフィックスとWi-Fiハードウェア(略)にチェック
  5. デュアルブートは想定していないので「ディスクを削除してUbuntuをインストール」を選択
  6. 続ける
  7. Tokyo
  8. ユーザ名とパスワード入力
  9. 〜〜インストール〜〜
  10. 今すぐ再起動
  11. 再びインストールの画面が出てくる
  12. Window右上のバツ印をクリックし、Quit
  13. Ctrl+Alt+Tでターミナルを立ち上げる
$ poweroff
  1. 電源が切れたらUSBメモリを抜く
  2. 電源ボタンを押し起動

基本設定

  1. 不完全な言語サポートのメッセージがでたら無視せず、指示に従ったほうが良い
  2. 以下のコマンドを入力
$ sudo apt-get update
$ sudo apt-get -y upgrade
$ sudo apt-get -y install vim
$ sudo apt-get -y install git

スワップ領域の拡張

最初にfreeコマンドで現在のメモリとスワップ領域を確認

$ free
              total        used        free      shared  buff/cache   available
Mem:       16291632     1054432    14473436       24072      763764    14916804
Swap:       2097148           0     2097148

続いて以下のコマンドを入力

$ sudo mkdir /var/swap/
$ sudo dd if=/dev/zero of=/var/swap/swap0 bs=1G count=16 #1GBのブロックを16個作成
16+0 レコード入力
16+0 レコード出力
17179869184 bytes (17 GB, 16 GiB) copied, 59.3778 s, 289 MB/s
$ sudo chmod 600 /var/swap/swap0
$ sudo mkswap /var/swap/swap0
スワップ空間バージョン 1 を設定します。サイズ = 16 GiB (17179865088 バイト)
ラベルはありません, UUID=dfaf906a-c807-4bdb-ad29-cf79b35109a8
$ sudo swapon /var/swap/swap0

以下を最後の行に記入

$ sudo vi /etc/fstab
/var/swap/swap0                           swap            swap    defaults        0       0

最後にスワップ領域が拡張されていることを確認

$ free
              total        used        free      shared  buff/cache   available
Mem:       16288956     1597732     1074256      129600    13616968    14204824
Swap:      18874360           0    18874360

再起動

$ reboot

再起動後にスワップ領域がマウントされていることを確認

$ free
              total        used        free      shared  buff/cache   available
Mem:       16288956      875120    14741400       22820      672436    15095312
Swap:      18874360           0    18874360

ホームディレクトリを英語にする

$ LANG=C xdg-user-dirs-gtk-update

タイムゾーンを合わせる

デフォルトでは9時間ずれている可能性があるため、以下を実行して日本時間に合わせる(これをやらないと正常に動作しないソフトや関数が存在するため)

まず、NTPサーバがインストールされているかの確認

$ sudo dpkg -l | grep ntp

なければインストール

$ sudo apt-get -y install ntp 

ルートでログイン

$ sudo su -

関連するパッケージのインストール

# sudo apt-get install ntpdate 
# sudo apt-get -y install ntpsec-ntpdate
# ntpdate ntp.nict.jp
ntpdig: no eligible servers

的確なサーバがないと言われるが、この3つのコマンドを実行すれば時間があう。 ここで最初に確認したコマンドを再入力してみる

$ sudo dpkg -l | grep ntp
ii  ntp                                        1:4.2.8p10+dfsg-5ubuntu7.1                   amd64        Network Time Protocol daemon and utility programs
rc  ntpdate                                    1:4.2.8p10+dfsg-5ubuntu7.1                   amd64        client for setting system time from NTP servers
ii  ntpsec-ntpdate                             1.1.0+dfsg1-1ubuntu0.2                       amd64        client for setting system time from NTP servers
ii  python3-ntp                                1.1.0+dfsg1-1ubuntu0.2                       amd64        Python 3 NTP Helper Classes
ii  sntp                                       1:4.2.8p10+dfsg-5ubuntu7.1                   amd64        Network Time Protocol - sntp client

このようになっていれば問題ないかと。

HDDの取り付け

f:id:AtsuyaKoike:20190807195806p:plain:w500

当然現段階ではHDDは外したままなので認識していません。 電源を落としたあと、PCにHDDを接続しカバー等をつけて元通りに。

f:id:AtsuyaKoike:20190807200541p:plain:w500

特に何もしなくてもHDDが認識されていることがわかる。


スワップ領域の拡張については以下のサイトを参考にさせていただきました。
Ubuntu Server 18.04 LTS スワップファイル設定

タイムゾーンの設定については以下のサイトを参考にさせていただきました。

Linuxサーバの時刻設定手順とエラー(the NTP socket is in use, exiting) - Qiita

【ROS】urdfでparentとchildの関係性を調べる

wiki.ros.org こちらを見ながら進めていった。

myfirst.urdf

<?xml version="1.0"?>
<robot name="myfirst">
  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      </geometry>
    </visual>
  </link>
</robot>
$ roslaunch urdf_tutorial display.launch model:=myfirst.urdf 

f:id:AtsuyaKoike:20190626191721p:plain:w400

lengthはz軸の長さ、radiusは半径でy軸。

03-origins.urdf

<?xml version="1.0"?>
<robot name="origins">
  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      </geometry>
    </visual>
  </link>

  <link name="right_leg">
    <visual>
      <geometry>
        <box size="0.6 0.1 0.2"/>
      </geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
    </visual>
  </link>

  <joint name="base_to_right_leg" type="fixed">
    <parent link="base_link"/>
    <child link="right_leg"/>
    <origin xyz="0 -0.22 0.25"/>
  </joint>

</robot>
$ roslaunch urdf_tutorial display.launch model:=03-origins.urdf 

f:id:AtsuyaKoike:20190626192015p:plain:w400

このurdfファイルでこの位置に持っていくことができるみたいだが、rpy、xyzを1つ1つ見ていかないと分からなくなりそうなので、試した結果を載せていく。 いじる部分は

right_legの

<origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>

と base_to_right_legの

<origin xyz="0 -0.22 0.25"/>

の部分

パターン1

right_leg:origin rpy="0 0 0" xyz="0 0 0"
base_to_right_leg:origin xyz="0 0 0"

f:id:AtsuyaKoike:20190626195128p:plain:w400

パターン2

right_leg:origin rpy="0 1.57075 0" xyz="0 0 0"
base_to_right_leg:origin xyz="0 0 0"

f:id:AtsuyaKoike:20190626195302p:plain:w400

パターン3

right_leg:origin rpy="0 1.57075 0" xyz="0 -0.3 0"
base_to_right_leg:origin xyz="0 0 0"

f:id:AtsuyaKoike:20190626195433p:plain:w400

パターン4

right_leg:origin rpy="0 1.57075 0" xyz="0 -0.3 0"
base_to_right_leg:origin xyz="0 0.22 0"

f:id:AtsuyaKoike:20190626195548p:plain:w400

パターン5

right_leg:origin rpy="0 1.57075 0" xyz="0 -0.3 0"
base_to_right_leg:origin xyz="0 0.22 0.25"

f:id:AtsuyaKoike:20190626195640p:plain:w400

これで、rpy、xyzを弄るときに参考になるはず。

棒を両サイドに出現させる

04-materials.urdf

<?xml version="1.0"?>
<robot name="materials">

  <material name="blue">
    <color rgba="0 0 0.8 1"/>
  </material>

  <material name="white">
    <color rgba="1 1 1 1"/>
  </material>


  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      </geometry>
      <material name="blue"/>
    </visual>
  </link>

  <link name="right_leg">
    <visual>
      <geometry>
        <box size="0.6 0.1 0.2"/>
      </geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
      <material name="white"/>
    </visual>
  </link>

  <joint name="base_to_right_leg" type="fixed">
    <parent link="base_link"/>
    <child link="right_leg"/>
    <origin xyz="0 -0.22 0.25"/>
  </joint>

  <link name="left_leg">
    <visual>
      <geometry>
        <box size="0.6 0.1 0.2"/>
      </geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
      <material name="white"/>
    </visual>
  </link>

  <joint name="base_to_left_leg" type="fixed">
    <parent link="base_link"/>
    <child link="left_leg"/>
    <origin xyz="0 0.22 0.25"/>
  </joint>

</robot>

f:id:AtsuyaKoike:20190626200906p:plain

簡単ですね。

【C++】vectorでpairを使うメモ

f:id:AtsuyaKoike:20190524095847p:plain:w300

最初に

vectorではpairが用いられることが多いようなので、C++vectorとpairを使った動作を備忘録として残します。

vector_pair.cpp

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec;
    vec.push_back(2);    
    vec.push_back(7);    
    vec.push_back(0);    
    vec.push_back(3);    
    vec.push_back(5);    
    vec.push_back(1);    
    vec.push_back(4);    
    vec.push_back(6);    
    vec.push_back(9);    
    vec.push_back(8);    

    typedef std::pair<int, int> pair;
    std::vector<pair> pair_vec;
    
    for ( int i = 0; i < vec.size(); ++i )
        pair_vec.push_back( pair( i, vec[i] ) );
        
    for ( auto& i: pair_vec )
        std::cout << i.first << " " << i.second << std::endl;

    return 0;

}

実行結果

$ g++ -o vector_pair vector_pair.cpp -std=c++11
$ ./vector_pair
0 2
1 7
2 0
3 3
4 5
5 1
6 4
7 6
8 9
9 8

解説

先に書かせていただくと、using namespace std;を使えば楽にかけますが、勉強のため。

  • 5行目:int型のベクトルの型を作成。
  • 6から15行目はvecに適当な縦10で横1の行列を作成。
  • 17行目では、pair<int, int>で2つ数字をセットにできる型を作成。
  • 18行目では、横の要素数が2つのpair_vecの行列の型を作成。
  • 23行目は範囲指定のfor文。C++11の機能を使っている。
  • 24行目は出力。pairの場合、ひとつ目がfirst, 2つめがsecondという扱い

まとめ

  • おそらく、pairを使わない場合はvector<vector>など面倒くさい書き方になるのを考えると、pairを使うと簡潔なプログラムになる
  • コンパイルする際にC++11の機能を使うオプションをつけないといけないため、現在の書き方を知る必要はあるかもです。(調べてもでてこないので、コンパイルオプションをつけるのは一般的?

以上です。

【C++】コピーコンストラクタ

f:id:AtsuyaKoike:20190524095847p:plain:w300

これまでの方法だと

  • オブジェクトを関数に渡す
  • 関数からオブジェクトを返す

ときに問題が発生した。

具体的には

  • オブジェクトを関数に渡すと、そのオブジェクトのコピーが作成され、オブジェクトを受け付ける関数の引数として使用される
    • 割り当てられたメモリのポインタを含むオブジェクトがある場合、コピーオブジェクトは元のオブジェクトと同じメモリを指す
      • コピーオブジェクトでこのメモリに変更を加えると、元のオブジェクトに影響
    • 関数の終了時に、コピーオブジェクトが破棄されデストラクタが呼び出されることで影響

  • 関数からオブジェクトを返す場合
    • 関数から返す値を保持する一時オブジェクトを作成する
      • 呼び出し元のルーチンに返した後は、スコープを外れデストラクタが呼び出される
      • これが動的メモリの場合に問題が生じる

  • コピーコンストラクタは
    • 1つのオブジェクトを使用して他のオブジェクトを初期化する方法を指定できる
    • コピーコンストラクタは、そのオブジェクトを使って他のオブジェクトを初期化するときに呼出される

study152.cpp

#include <iostream>
#include <cstdlib>
using namespace std;

class array {
    int *p;
    int size;
public:
    array( int sz ) {
        p = new int[sz];
        if( !p ) {
            exit(1);
        }
        size = sz;
        cout << "通常のコンストラクタを使う\n";
    }
    ~array() {
        delete [] p;
    }
    
    array( const array &a );

    void put( int i, int j ) {
        if ( i >= 0 && i < size ) {
            p[i] = j;
        }
    }
    int get( int i ) {
        return p[i];
    }
};

array::array( const array &a ) {
    size = a.size;
    p = new int[a.size];
    if( !p ) {
        exit(1);
    }
    for( int i = 0; i < a.size; i++ ) {
        p[i] = a.p[i];
    }
    cout << "コピーコンストラクタを使用\n";
}

int main() {
    array num(10);
    
    for ( int i = 0; i < 10; ++i ) {
        num.put( i, i );
    }

    for ( int i = 0; i < 10; ++i ) {
        cout << num.get(i);
    }
    cout << "\n";

    array x = num;

    for ( int i = 0; i < 10; ++i ) {
        cout << x.get(i);
    }
    cout << "\n";

    return 0;
}
 ./study152 
通常のコンストラクタを使う
0123456789
コピーコンストラクタを使用
0123456789

study156.cpp

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;

class strtype {
    char *p;
public:
    strtype( char *s );
    strtype( const strtype &o );
    ~strtype() {
        delete [] p;
    }
    char *get() {
        return p;
    }
};

strtype::strtype( char *s ) {
    int l;
    l = strlen(s) + 1;

    p = new char [l];
    if ( !p ) {
        cout << "メモリ割り当てエラー\n";
        exit(1);
    }
    strcpy( p, s );
}

strtype::strtype( const strtype &o ) {
    int l;
    l = strlen(o.p) + 1;

    p = new char [l];
    if ( !p ) {
        cout << "メモリ割り当てエラー\n";
        exit(1);
    }
    strcpy( p, o.p );
}

void show( strtype x ) {
    char *s;

    s = x.get();
    cout << s << "\n";
}

int main() {
    strtype a("Hello"), b("There");
    
    show(a);
    show(b);

    return 0;
}
  • 関数へオブジェクトを引き渡すときにコピーが作成されるが、その設定をコピーコンストラクタが行う
  • コピー作成時にコピー用のメモリを割り当てる
    • show()終了時にスコープから外れ、x.pが指すメモリが開放されるが、これは関数に渡した元のオブジェクトのメモリとは異なる。




引用・参考はこちら

f:id:AtsuyaKoike:20190524100759j:plain:w200
独習C++ 第4版 https://www.amazon.co.jp/dp/4798119768