C++

boost::scoped_ptr/boost::checked_delete

boost::scoped_ptrはデストラクタが定義されていないとエラーになるという話がなかなかわかったが、人から説明をうけてやっとわかった。
  • http://twitter.com/SubaruG/status/14747212751
  • http://twitter.com/SubaruG/status/14747268037
  • http://twitter.com/SubaruG/status/14747325492
=== main.cc ===
     1  #include "hoge.h"
     2  int
     3  main()
     4  {
     5      hoge h;
     6  }
=== hoge.h ===
     1  #include <boost/scoped_ptr.hpp>
     2  struct hoge
     3  {
     4      hoge();
     5      ~hoge() {} //もしデストラクタをユーザ定義しないとすると、コンパイラがデフォルトでこんなのを生成する
     6   private:
     7      class impl;
     8      boost::scoped_ptr<impl> pimpl_;
     9  };
=== impl.cc ===
     1  #include "hoge.h"
     2  #include <iostream>
     3  struct hoge::impl
     4  {
     5      impl() { std::cout << "impl+" << std::endl; }
     6      ~impl() { std::cout << "impl-" << std::endl; }
     7  };
     8  hoge::hoge() : pimpl_(new hoge::impl) {}

% c++ -I/usr/local/include -c main.cc
/usr/local/include/boost/checked_delete.hpp: In function 'void boost::checked_delete(T*) [with T = hoge::impl]':
/usr/local/include/boost/smart_ptr/scoped_ptr.hpp:80:   instantiated from 'boost::scoped_ptr::~scoped_ptr() [with T = hoge::impl]'
hoge.h:5:   instantiated from here
/usr/local/include/boost/checked_delete.hpp:32: error: invalid application of 'sizeof' to incomplete type 'hoge::impl'
/usr/local/include/boost/checked_delete.hpp:32: error: creating array with negative size ('-0x00000000000000001')
/usr/local/include/boost/checked_delete.hpp:33: error: invalid application of 'sizeof' to incomplete type 'hoge::impl'
/usr/local/include/boost/checked_delete.hpp:33: error: creating array with negative size ('-0x00000000000000001')
/usr/local/include/boost/checked_delete.hpp:34: warning: possible problem detected in invocation of delete operator:
/usr/local/include/boost/checked_delete.hpp:29: warning: 'x' has incomplete type
hoge.h:7: warning: forward declaration of 'struct hoge::impl'
/usr/local/include/boost/checked_delete.hpp:34: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.
*** Error code 1
なぜメンバ変数 piml_ の実体化のところで、その外にあるクラスのデストラクタの有無が影響してくるのかだが、
  1. hoge のデストラクタが定義されてないので main.cc の中でデフォルトで生成される。
  2. よってメンバ変数のpimpl_ のデストラクタを main.cc の中で実体化する必要がある。
  3. よってデストラクタの中で使われている boost::checked_delete<impl>() も実体化される。
  4. だが impl は定義がない不完全型なので sizeof が失敗してエラーになる。

BOOST_FOREACHの引数コンマ問題

BOOST_FOREACHはつかったことがないんだけども、 ループ変数の定義の中にコンマが含まれていると、マクロの引数の区切りのコンマと間違えられてエラーになるということがあるらしい。 Pitfallsにあるtypedefする方法と外部で定義する方法以外にこんなのはどうか。
#include <map>
#include <boost/foreach.hpp>
#include <iostream>
int
main()
{
    std::map<int, int> m;
    m[1]=1;
    m[2]=4;
    m[3]=9;
#if 0
    BOOST_FOREACH(std::map<int, int>::value_type const& iter, m)
    {
        std::cout<<iter.second<<std::endl;
    }
#endif
#define THRU(X,...) X,__VA_ARGS__
    BOOST_FOREACH(THRU(std::map<int, int>::value_type const& iter), m)
    {
        std::cout<<iter.second<<std::endl;
    }
    BOOST_FOREACH(auto iter, m)
    {
        std::cout<<iter.second<<std::endl;
    }
    return 0;
}

C++0x extended initializer lists

boostに知らないことがいっぱいあってもあきらめがつくが C++0xで知らないことだらけなのはちょっとあせる。
one-phase constructionについて N3059まとめ をみてみると C++0x Uniform initializationというのがあるらしくて変数の初期化に () ではなくて {} がつかえるそうだ。 C++0x Uniform initializationとか C++0x - 初期化子リスト(Initializer List)とか
struct S
{
    int a;
    const char* b;
};
struct T
{
    int a;
    T(int b) : a{b} {} //あたらしいやりかた
    //T(int b) : a = b {} -> NG
};
int
main()
{
    S s1 = { 1, "1" }; //いままでどおり
    S s2 { 2, "2" };   //これがあたらしいやりかた
    T t (3);
    int v[4] {1,2,3,4}; // = がなくてもよい
    return 0;
}
koie

tailcall最適化

C++のiostreamを使った関数の書き方で最後の関数呼び出しがtailcallになることにいまさら気づいた。いままでnontailcallの書き方をしていたが、それはインライン展開されたときに<<の戻り値に依存しなくなって最適化が効きやすいかと思ったからだったが、奥が深い。
% cat -n tailcall.cc
     1  #include <iostream>
     2  using namespace std;
     3  ostream& nontailcall(ostream&);
     4  ostream& tailcall(ostream&);
     5  int
     6  main()
     7  {
     8      nontailcall(cout);
     9      tailcall(cout);
    10  }
    11  ostream& nontailcall(ostream& ost)
    12  {
    13      ost << 1;
    14      return ost;
    15  }
    16  ostream& tailcall(ostream& ost)
    17  {
    18      return ost << 1;
    19  }
% g++ -O9 tailcall.cc -o tailcall
% objdump -d tailcall | c++filt

tailcall:     file format elf64-x86-64-freebsd

....[snip]....

Disassembly of section .text:

....[snip]....

0000000000400790 <tailcall(std::basic_ostream<char, std::char_traits<char> >&)>:
  400790:       be 01 00 00 00          mov    $0x1,%esi
  400795:       e9 6a fe ff ff          jmpq   400604 <std::basic_ostream<char, std::char_traits<char> >::operator<<(int)@plt>
  40079a:       66 66 90                xchg   %ax,%ax
  40079d:       66 66 90                xchg   %ax,%ax

00000000004007a0 <nontailcall(std::basic_ostream<char, std::char_traits<char> >&)>:
  4007a0:       53                      push   %rbx
  4007a1:       be 01 00 00 00          mov    $0x1,%esi
  4007a6:       48 89 fb                mov    %rdi,%rbx
  4007a9:       e8 56 fe ff ff          callq  400604 <std::basic_ostream<char, std::char_traits<char> >::operator<<(int)@plt>
  4007ae:       48 89 d8                mov    %rbx,%rax
  4007b1:       5b                      pop    %rbx
  4007b2:       c3                      retq
  4007b3:       90                      nop
  4007b4:       66 66 66 90             xchg   %ax,%ax
  4007b8:       66 66 66 90             xchg   %ax,%ax
  4007bc:       66 66 66 90             xchg   %ax,%ax

....[snip]....

gdb-stl-views

STLのコンテナをみやすく表示してくれるgdbマクロ gdb-stl-views
% cat -n foo.cc
     1  #include <map>
     2  #include <vector>
     3  #include <list>
     4  using namespace std;
     5
     6  void f() { }
     7
     8  int
     9  main()
    10  {
    11      map<int,double> m;
    12      m[0] = 0.0;
    13      m[1] = 0.1;
    14      m[2] = 0.2;
    15
    16      vector<int> v;
    17      v.push_back(1);
    18      v.push_back(2);
    19      v.push_back(3);
    20
    21      list<int> lst;
    22      lst.push_back(10);
    23      lst.push_back(20);
    24      lst.push_back(30);
    25
    26      f();
    27  }
% c++ -g foo.cc -o foo
% gdb foo
GNU gdb Fedora (6.8-37.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu"...
(gdb) break f
Breakpoint 1 at 0x40092c: file foo.cc, line 6.
(gdb) run
Starting program: /home/koie/.../foo

Breakpoint 1, f () at foo.cc:6
6       void f() { }
(gdb) up
#1  0x0000000000400a71 in main () at foo.cc:26
26          f();
(gdb) print v
$1 = {<std::_Vector_base<int,std::allocator<int> >> = {
    _M_impl = {<std::allocator<int>> = {<__gnu_cxx::new_allocator<int>> = {<No data fields>}, <No data fields>}, _M_start = 0x1e4690d0,
      _M_finish = 0x1e4690dc,
      _M_end_of_storage = 0x1e4690e0}}, <No data fields>}
(gdb) source stl-views-1.0.3.gdb
(gdb) pvector v
elem[0]: $2 = 1
elem[1]: $3 = 2
elem[2]: $4 = 3
Vector size = 3
Vector capacity = 4
Element type = int *
(gdb) pmap m
Map type =
    std::map<int,double,std::less<int>,std::allocator<std::pair<const int, double> > >
Use pmap <variable_name> <left_element_type> <right_element_type> to see the elements in the map.
Map size = 3
(gdb) plist lst
List size = 3
List type = std::list<int,std::allocator<int> >
Use plist <variable_name> <element_type> to see the elements in the list.
(gdb) quit
記事検索
月別アーカイブ
アクセスカウンター

    タグ絞り込み検索
    ギャラリー
    • 今日の練習 2025-01-10
    • エディオン オリジナルLEDライト
    • エディオン オリジナルLEDライト
    • エディオン オリジナルLEDライト
    • エディオン オリジナルLEDライト
    • 今日の練習 2025-01-07
    Amazon
    楽天市場
    adby google
    LINE読者登録QRコード
    LINE読者登録QRコード