2017-03-17 17 views
2

私はboost::shared_ptrしかかからない関数(私は制御しない)にスタック変数へのポインタを渡そうとしています。テンプレート引数なしでmake_sharedをブースト

this answerによれば、boost::make_sharedを使用しています。この機能をテストするために私はこれを書いた:

#include <iostream> 
#include <boost/shared_ptr.hpp> 
#include <boost/make_shared.hpp> 

int main(int argc, char const *argv[]) 
{ 
    int i = 10; 
    boost::shared_ptr<int> int_ptr = boost::make_shared(i); // doesn't work 
    some_function(int_ptr); // this function takes only shared_ptr 
    return 0; 
} 

をしかし、それは次のようなエラーがスローされます。

error: no matching function for call to ‘make_shared(int&)’ 
boost::shared_ptr<int> int_ptr = boost::make_shared(i); 
                ^

私は次のようにテンプレート引数を追加した場合ので、それは動作しますが、その理由は何ですか?

boost::shared_ptr<int> int_ptr = boost::make_shared<int>(i); 

ありがとうございます!

namespace boost { 
    template<typename T, typename Arg1> 
     shared_ptr<T> make_shared(Arg1 const & arg1); 
} 

テンプレートメカニズムは、パラメータarg1の種類を推測することができます

+4

「int」を与えるだけであれば、どのようなタイプの共有ポインタを使うべきか自問してください。 'shared_ptr 'が必要で、 'shared_ptr 'は' int'で構築することはできません。 – NathanOliver

+0

テンプレート引数の減算には、結果が割り当てられるタイプに関する情報を含めることはできません。 'boost :: shared_ptr int_ptr ='部分は、適切なテンプレート引数を決定するために考慮に入れられません。 –

+2

スタック割り当てメモリを指す 'shared_ptr'を作成すると、そのメモリを削除しようとすると悲惨です。 'i'はポインタを通して変更可能である必要がありますか、' 'i''のコピーで十分でしょうか? – chris

答えて

3

boost::make_shared<T>テンプレートを考えます。これは引数の型が「i」(「int」)の「見える」ためです。ただし、返品タイプTを推論することはできません。それはboost::shared_ptr<T>あなたがに割り当てるの種類T知らない(それはint_ptrの種類を知るための手段を持たないすなわち。)

boost::shared_ptr<T>はあなたをできるように、さまざまな引数の型(Arg1)とリターン(T)を使用していますポインタ型とは異なる引数から共有ポインタを構築します。しばらくその

念頭に
template<typename T> 
boost::shared_ptr<T> my_make_shared(T const & arg) { 
    return boost::make_shared<T>(arg); 
} 

しかしクマ:例えば、doubleintへ:

double d = 10.0; 
std::shared_ptr<int> int_ptr = std::make_shared<int>(d); 

あなたはタイプが引数と同じである共有ポインタを構築したい場合は、ラッパーを書くことができますこれは動作します:

int i = 10.0; 
std::shared_ptr<int> int_ptr = my_make_shared(i); // OK 

暗黙の型変換がない:

double d = 10.0; 
std::shared_ptr<int> int_ptr = my_make_shared(d); // ERROR 

希望すると助かります!

+0

'shared_ptr 'が 'double 'を指していることは何を意味しますか? – simplename

+1

実際には 'shared_ptr 'は 'double'を指していません。しかし 'make_shared 'が 'int'のためにメモリを割り当てると' double'の値でメモリを初期化します。 –

0

ギルヘルム・フェレイラの答えは、テンプレート引数の控除を詳しく説明しています(これに関しては正しい)、これはあなたが探している答えではないと私は信じています。

I'm trying to pass a pointer to a stack variable to a function (I don't control) that only takes a boost::shared_ptr.

shared_ptrは、ポイント付きオブジェクトに対する共有所有権を意味します。呼び出ししようとしている関数が、コンテナのようなデータ構造体の一部にポインタを保存してから戻ると、ポインタは、shared_ptrがまだ保持されているにもかかわらず、スタックの値が破棄されるとすぐにぶら下がります参照。あなたが望むことをするためには、関数がポインタをどこにも保存せず、この1回の呼び出しの間にしかポインタを使用できないことを絶対に確かめる必要があります。

この条件が満たされている場合は、スタック上の値を指すshared_ptrを作成できますが、そのためにはmake_sharedを使用することはできません。make_sharedはヒープ上に新しいオブジェクトを割り当て、参照カウンタとともに関数呼び出しに渡した引数で初期化します。返されたshared_ptrは、新しいオブジェクトを指し、スタック上のオブジェクトを指しません。

void foo() 
{ 
    int n = 10; 
    boost::shared_ptr<int> pn = boost::make_shared<int>(n); 

    assert(*pn == 10); // succeeds 
    assert(pn.get() == &n); // fails 

    bar(pn); 
} 

これは尖ったintになるbar修正がnに反映されていないことを意味します。

既存のオブジェクトにshared_ptrを作成するには、そのコンストラクタを直接使用する必要があります。また、オブジェクトの寿命はスタックによって制御されるため、shared_ptrがオブジェクトを破棄することを禁止する必要があります。これは、shared_ptrの構築時にノーオペレータを指定することで実行できます。

void foo() 
{ 
    int n = 10; 
    boost::shared_ptr<int> pn(&n, boost::null_deleter()); 

    assert(*pn == 10); // succeeds 
    assert(pn.get() == &n); // succeeds 

    bar(pn); 
} 

注意は、しかし、このコードはまだ参照カウンタshared_ptr用途のためにヒープメモリを割り当てることを、あなたはどんなパフォーマンスを獲得していません。