STLのカスタムアロケータでスマートポインタを使いたい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
みょーが

STLのカスタムアロケータでスマートポインタを使いたい

#1

投稿記事 by みょーが » 9年前

コード:

template <typename T>
class stl_allocator
{
public:
    using value_type = T;
    using pointer = std::shared_ptr<T[]>;

    stl_allocator() = default;

    template <typename U>
    stl_allocator(stl_allocator<U> const&) {}

    pointer allocate(std::size_t n)
    {
        return pointer{::new T[n]};
    }

    void deallocate(pointer, std::size_t) {}

    template <typename... Args>
    void construct(pointer p, Args&&... args)
    {
        ::new(p.get()) T{std::forward<Args>(args)...};
    }

    void destroy(pointer) {}

    template <typename U>
    bool operator ==(stl_allocator<U> const&) { return true; }

    template <typename U>
    bool operator !=(stl_allocator<U> const&) { return false; }
};

namespace std
{
    template <typename T>
    ptrdiff_t operator -(shared_ptr<T[]> const &lhs, shared_ptr<T[]> const &rhs)
    {
        return lhs.get() - rhs.get();
    }
}
一応、下記のリンク先(64ページ辺りからです)には出来るというような記述があるのですが、
どうにも私の環境(MSVC2015)ではコンパイルできません

deallocate の呼び出し時に 生のポインタを std::shared_ptr<T[]> に変換しようとして
失敗しているようなのですが...

カスタムアロケータの知識に乏しいもので、難解なテンプレートのエラーに悩まされております
必要なメンバ関数も足りていないかもしれません

更に、std::hash や std::default_delete などの特殊化は規格でも許容されていたはずですが、
operator - の追加は大丈夫なのか気になります

拙いコードと文章で申し訳ありませんがよろしくお願いします

[anchor= goto=http://www.slideshare.net/Cryolite/allocator11final]http://www.slideshare.net/Cryolite/allocator11final[/anchor]

sleep

Re: STLのカスタムアロケータでスマートポインタを使いたい

#2

投稿記事 by sleep » 9年前

みょーが さんが書きました: deallocate の呼び出し時に 生のポインタを std::shared_ptr<T[]> に変換しようとして
失敗しているようなのですが...
いえ、失敗しているのは pointer allocate(std::size_t n) の pointer{::new T[n]} です。
T*(つまり、::new T[n])を T (*)[](using pointer = std::shared_ptr<T[]> で定義されてある通り T(*)[])へ変換しようとしているだけです。
std::unique_ptrは特殊化されているので std::unique_ptr<T[]> のような指定ができますが、std::shared_ptrは特殊化されていないのでできません。なので、std::shared_ptr で配列を使用する場合、解放は自分で指定する必要があります。

コード:

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

class A
{
public:
	~A()
	{
		cout << "デストラクタ" << endl;
	}
};

int main()
{
	{
		shared_ptr<A> a(new A[10], default_delete<A[]>());
	}
	cin.ignore();
}

みょーが

Re: STLのカスタムアロケータでスマートポインタを使いたい

#3

投稿記事 by みょーが » 9年前

ご回答ありがとうございます
sleep さんが書きました:std::unique_ptrは特殊化されているので std::unique_ptr<T[]> のような指定ができますが、std::shared_ptrは特殊化されていないのでできません。
なるほど、失念していました
早速修正してみたのですが、エラーメッセージが変わる気配がありません

std::shared_ptr が配列への特殊化を持たないということは、配列アクセスも出来ないのですか?
となれば生ポインタに依存したコードはコンパイルできませんよね

配列アクセスもそうですけど、shared_ptr はインクリメントもデクリメントもできません
アロケータ云々以前にポインタを扱うコードにかますことが出来ないような気がしてきました

一応、エラーの重要そうな部分を抜粋してみました
typename std::allocator_traits<stl_allocator<T>>::pointer が std::shared_ptr<T[]> に
なっていないような気がします

1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\vector(590): error C2664: 'void std::_Wrap_alloc<stl_allocator<_Newfirst>>::deallocate(std::shared_ptr<T []>,unsigned __int64)': 引数 1 を 'std::_Container_proxy *' から 'std::shared_ptr<T []>' へ変換できません。
1> with
1> [
1> _Newfirst=std::_Container_proxy,
1> T=std::_Container_proxy
1> ]
1> and
1> [
1> T=std::_Container_proxy
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\vector(590): note: class 'std::shared_ptr<T []>' のコンストラクターが 'explicit' と宣言されています。
1> with
1> [
1> T=std::_Container_proxy
1> ]

sleep

Re: STLのカスタムアロケータでスマートポインタを使いたい

#4

投稿記事 by sleep » 9年前

みょーが さんが書きました: 一応、下記のリンク先(64ページ辺りからです)には出来るというような記述があるのですが、
どうにも私の環境(MSVC2015)ではコンパイルできません

deallocate の呼び出し時に 生のポインタを std::shared_ptr<T[]> に変換しようとして
失敗しているようなのですが...
みょーが さんが書きました: 早速修正してみたのですが、エラーメッセージが変わる気配がありません
コンパイルできると思いますが?

コード:

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

template <typename T>
class stl_allocator
{
public:
	using value_type = T;
	using pointer = std::shared_ptr<T>;

	stl_allocator() = default;

	template <typename U>
	stl_allocator(stl_allocator<U> const&) {}

	pointer allocate(std::size_t n)
	{
		return pointer{ ::new T[n], default_delete<A[]>() };
	}

	void deallocate(pointer, std::size_t) {}

	template <typename... Args>
	void construct(pointer p, Args&&... args)
	{
		::new(p.get()) T{ std::forward<Args>(args)... };
	}

	void destroy(pointer) {}

	template <typename U>
	bool operator ==(stl_allocator<U> const&) { return true; }

	template <typename U>
	bool operator !=(stl_allocator<U> const&) { return false; }
};

namespace std
{
	template <typename T>
	ptrdiff_t operator -(shared_ptr<T[]> const &lhs, shared_ptr<T[]> const &rhs)
	{
		return lhs.get() - rhs.get();
	}
}

class A
{
public:
	~A()
	{
		cout << "デストラクタ" << endl;
	}
};

int main()
{
	auto a = stl_allocator<A>();
	{
		auto b = a.allocate(10);
	}
	cin.ignore();
}
あと、質問が何なのかよく分かりません。

sleep

Re: STLのカスタムアロケータでスマートポインタを使いたい

#5

投稿記事 by sleep » 9年前

sleep さんが書きました:

コード:

		return pointer{ ::new T[n], default_delete<A[]>() };
訂正:

コード:

		return pointer{ ::new T[n], default_delete<T[]>() };

みょーが

Re: STLのカスタムアロケータでスマートポインタを使いたい

#6

投稿記事 by みょーが » 9年前

それはコンパイル出来ますが、STLのアロケータを単体で使用する場面ってあるのでしょうか

コード:

std::vector<int, stl_allocator<int>> v;
これはコンパイル出来ますか?

質問内容は、

スマートポインタをpointer型に据えた、コンパイルできるようなアロケータの定義を教えてください
STLコンテナのアロケータに指定して使うことを想定しています

となります

sleep

Re: STLのカスタムアロケータでスマートポインタを使いたい

#7

投稿記事 by sleep » 9年前

みょーが さんが書きました: それはコンパイル出来ますが、STLのアロケータを単体で使用する場面ってあるのでしょうか

コード:

std::vector<int, stl_allocator<int>> v;
これはコンパイル出来ますか?
随分上から目線な方ですね。
見直しましたが、No.1はどう見ても「提示したコードのコンパイルが通りません」という文面にしか見えません。
少なくとも「アロケータを私の代わりに作ってください」という依頼の文面には見えないですね。
みょーが さんが書きました: 質問内容は、

スマートポインタをpointer型に据えた、コンパイルできるようなアロケータの定義を教えてください
STLコンテナのアロケータに指定して使うことを想定しています

となります
「私は全く分かりません。私の代わりにプログラムを書いてください」は依頼であって質問ではないので、他の方に依頼してください。

みょーが

Re: STLのカスタムアロケータでスマートポインタを使いたい

#8

投稿記事 by みょーが » 9年前

上から目線、というような意図はなかったのですが、確かにそう見える文章ですね
申し訳ありません

丸投げするつもりはありませんが、当方では既に行き詰まっておりますので、他の方の回答を待つことにします

お世話になりました

閉鎖

“C言語何でも質問掲示板” へ戻る