| | 546 | |
| | 547 | == 実践 shared_ptr == |
| | 548 | |
| | 549 | === ガベコレ === |
| | 550 | |
| | 551 | * GC のほうが適した問題領域も… |
| | 552 | * 無いものはないので我慢 |
| | 553 | |
| | 554 | === カスタムデリータ === |
| | 555 | |
| | 556 | * 動的にリソースの解放方法を決める |
| | 557 | * 所有者が居なくなったら呼ばれる (参照カウンタ) |
| | 558 | * 同じ型でも確保、解放処理は異なる |
| | 559 | * shared_ptr = カウンタ + デリータ |
| | 560 | * 大事です |
| | 561 | |
| | 562 | === 具体例 === |
| | 563 | |
| | 564 | * boost::checked_deleter |
| | 565 | * 単に delete する |
| | 566 | * boost::checked_array_deleter |
| | 567 | * delete[] |
| | 568 | * 関数 (オブジェクト) なので何でもできます |
| | 569 | * ログ仕込んだり… |
| | 570 | * 典型例: ハンドルのクローズ |
| | 571 | {{{ |
| | 572 | HHOGE raw_handle = ::OpenHoge(...); |
| | 573 | ::ReleaseHoge(raw_handle); |
| | 574 | }}} |
| | 575 | * 確実にハンドルをクローズするには…? |
| | 576 | * 勝手に解放して下さい |
| | 577 | {{{ |
| | 578 | typedef |
| | 579 | shared_ptr<remove_pointer<HHOGE>::type> |
| | 580 | HogePtr; |
| | 581 | HHOGE raw_handle = ::OpenHoge(...); |
| | 582 | HogePtr hoge_h(raw_handle, ::CloseHoge); |
| | 583 | }}} |
| | 584 | |
| | 585 | === リソース間の依存 === |
| | 586 | |
| | 587 | * 権利だけ主張する人もいます |
| | 588 | {{{ |
| | 589 | struct Legacy { |
| | 590 | Buffer* buffer; // ちゃんと有効なバッファ指してね! |
| | 591 | }; |
| | 592 | }}} |
| | 593 | * Legacy::buffer の管理は誰の責任? |
| | 594 | * 所有権ちょいたし |
| | 595 | {{{ |
| | 596 | struct LegacyDeleter { |
| | 597 | explicit LegacyDeleter(shared_ptr<Buffer> buffer) |
| | 598 | : buffer(buffer) {} |
| | 599 | void operator()(Legacy* ptr) const { delete ptr; } |
| | 600 | shared_ptr<Buffer> buffer; // 所有 |
| | 601 | }; |
| | 602 | shared_ptr<Legacy> create(shared_ptr<Buffer> buffer) { |
| | 603 | LegacyDeleter deleter(buffer); // デリータが所有 |
| | 604 | shared_ptr<Legacy> ret(new legacy(), deleter); |
| | 605 | ret->bufer = buffer.get(); |
| | 606 | return ret; |
| | 607 | }; |
| | 608 | }}} |
| | 609 | |
| | 610 | === Null デリータ === |
| | 611 | |
| | 612 | * 何もしないデリータです。 |
| | 613 | {{{ |
| | 614 | struct NullDeleter { |
| | 615 | void operator()(void*) const{} |
| | 616 | }; |
| | 617 | |
| | 618 | void nullDeleter(void *){ |
| | 619 | } |
| | 620 | }}} |
| | 621 | * 誰かが管理しているリソース |
| | 622 | * コンテキストと生死を共にしている |
| | 623 | * スタック、data領域、TLS ... |
| | 624 | * 何らかの仕組みで管理されている |
| | 625 | * 強調できるのが一番良いのですが… |
| | 626 | * ポインタのフリしてるだけ |
| | 627 | * reinterpret_cast<void *>(...) |
| | 628 | {{{ |
| | 629 | static vecter<int> vi; |
| | 630 | shared_ptr<vector<int> > vi_ptr(&vi, NullDeleter()); |
| | 631 | |
| | 632 | void* val = reinterpret_cast<void*>(-1); |
| | 633 | shared_ptr<void> val_ptr(val, NullDeleter()); |
| | 634 | |
| | 635 | shared_ptr<pair<int, int> > iip = ...; |
| | 636 | shared_ptr<int> iptr(&iip->first, NullDeleter()); |
| | 637 | }}} |
| | 638 | * ところで (上記 3つ目) もし iip が有効じゃなかったら… |
| | 639 | * 他の手を考えましょう。 |
| | 640 | * boost もしくは 0x なら... |
| | 641 | * 参照カウンタの共有! |
| | 642 | * iip.use_count() == iptr.use_count() |
| | 643 | * でも tr1 にはありません… |
| | 644 | * tr1 なら Null デリータ + 延命 |
| | 645 | {{{ |
| | 646 | struct FirstDeleter { |
| | 647 | explicet firstDeleter(shared_ptr<pair<int, int> > parent) |
| | 648 | :parent(parent){} |
| | 649 | void operator()(int*) const {}; |
| | 650 | shared_ptr<pair<int, int> > parent; |
| | 651 | }; |
| | 652 | |
| | 653 | === 応用 === |
| | 654 | |
| | 655 | * 参照はしたい、所有はしたくない、リソースが有効じゃなくても良い、でも安全だと嬉しい。 |
| | 656 | * ↑お前は何を(ry |
| | 657 | * どうしても所有してしまう |
| | 658 | {{{ |
| | 659 | weak_ptr<T> weak = ...; |
| | 660 | shared_ptr<T> ptr = weak.lock(); |
| | 661 | }}} |
| | 662 | * リソース安全に扱うための仕組み |
| | 663 | * 安全とか要らん |
| | 664 | * これでもくらえ |
| | 665 | {{{ |
| | 666 | struct Deleter { |
| | 667 | void operator()(T* ptr) const { not_onwer.reset(); ... } |
| | 668 | shared_ptr<T> not_owner; |
| | 669 | } deleter; |
| | 670 | shared_ptr<T> owner(ptr, deleter); |
| | 671 | deleter.not_owner.reset(owner.get(), NullDeleter()); |
| | 672 | weak_ptr<T> not_owner_ref = deleter.not_owner; |
| | 673 | }}} |
| | 674 | * ex) HWND ... ウィンドウを生成したのとは別のスレッドで解放してはいけない |
| | 675 | |
| | 676 | === 注意 === |
| | 677 | |
| | 678 | * コンテキストに注意 |
| | 679 | * デリータはどこでも呼び出される |
| | 680 | |
| | 681 | === みんな大好き void* === |
| | 682 | |
| | 683 | * 何でも参照できる魔法のポインタ型 |
| | 684 | * ただのポインタ |
| | 685 | * 参照なのか所有なのか? |
| | 686 | * 有効なのか無効なのか? |
| | 687 | * shared_ptr<void> |
| | 688 | {{{ |
| | 689 | vector<shared_ptr<void>> delay; |
| | 690 | delay.push_back(make_shared<int>(1)); |
| | 691 | delay.push_back(make_shared<string>("one")); |
| | 692 | }}} |
| | 693 | * 何でも入るぞ- |
| | 694 | * カスタムデリータ-で正しく解放できる |
| | 695 | * とりあえず寿命伸ばしたいときとかに |
| | 696 | * 実践例: Blob |
| | 697 | {{{ |
| | 698 | struct Blob { |
| | 699 | char* data; |
| | 700 | size_t size; |
| | 701 | shared_ptr<void> resource; |
| | 702 | }; |
| | 703 | }}} |
| | 704 | {{{ |
| | 705 | Blob createBlob(const vector<char>& v){ |
| | 706 | shared_ptr<vector<char>> res(new vector<char>(v)); |
| | 707 | return Blob(res->data().res->size(), res); |
| | 708 | } |
| | 709 | Blob createBlob(const string& str){ |
| | 710 | shared_ptr<string> res(new string(str)); |
| | 711 | return Blob(res->data().res->size(), res); |
| | 712 | } |
| | 713 | }}} |
| | 714 | |
| | 715 | === 複数のリソースを返す API === |
| | 716 | |
| | 717 | * unique_ptr -> shared_ptr |