質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

2回答

3427閲覧

配列版のstd::swapについて

JADEN

総合スコア106

C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

2グッド

1クリップ

投稿2016/03/19 04:05

編集2022/01/12 10:55

以下のサイトで、utilityヘッダの非配列版swapは、各型のムーブコンストラクタとムーブ代入演算を使用しています。
配列版swapでは、別ヘッダで実装されているswapを呼んでいます。
(オーバーロードが見つからなければ、utilityヘッダの非配列版swapが呼ばれる?)
swap - cpprefjp C++日本語リファレンス

utilityヘッダの配列版swapの処理で、配列要素に対して、utilityヘッダの非配列版swapを呼び出す処理ではいけないのでしょうか。
この様にすれば、別ヘッダのswapを実装する必要がなくなる気がします。

私が勘違いしているかもしれませんが、図を書きました。

図1. 実際の実装?
実際の実装

図2. 私の考え
私の考え

追記
文章を修正し、図を追加しました。
図を修正しました。

raccy, ikuwow👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

こんにちは。

「コンテナ」の意味が今ひとつ掴めませんが、リンク先のテンプレート仮引数のTと想定して回答してみます。外していたらごめんなさい。

配列版の処理において、ループで非配列版のswapを呼び出す処理ではいけないのでしょうか。

既にそのようになっていると思います。

リンク先でも軽く説明されている(誤解しやすいかも)ようですが、ADLを使って各型用のswapが実装されていたらそちらを呼び、そうでなければstd::swapを呼ぶ仕組みだそうです。


【追記された質問への回答】
もしかして、utilityのswap(配列版)の配列はstd::arrayやstd::vector等を指していると理解されていますでしょうか?
cpprefjpに記載されているswapの配列版はC/C++のネイティブな配列のみに対応しています。コンテナには対応していません。

C++

1template <class T, size_t N> 2void swap(T (&a)[N], T (&b)[N]);

におけるabはC/C++ネイティブ配列への参照です。

もし、swap(a, b);のa,bにコンテナを与えた場合、cpprefjpに記載されているswapの値版が呼ばれます。

投稿2016/03/19 08:17

編集2016/03/19 10:27
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

JADEN

2016/03/19 10:41

回答ありがとうございます。 >>aとbはC/C++ネイティブ配列への参照です。 型Tに対して、配列への参照を記述しているので、コンテナの配列にも対応していると思ったのですが、(例えばstd::vector[]) std::vector[]を与えた場合に、別ヘッダのswapを呼ばずに、std::vector[i]に対して、utilityヘッダの値版swapを呼べないのでしょうか。
Chironian

2016/03/19 11:08

std::vectorはoperator[]をオーバーライドしているだけなので、型としてT[N]のようなシグニチャになっているわけではないです。 swap(a, b,);のa, bにstd::vectorのインスタンスを与えた時に、swap(a[i], b[i])を呼びたいのですか? utilityヘッダのswapはそのような機能を持っていないようです。 <vector>に定義されているswapはたぶんそのようなものではないでしょうか? http://www.cplusplus.com/reference/vector/vector/swap-free/
JADEN

2016/03/19 11:43 編集

実際に実装されているswapは、以下の様になっていると思います。 namespace std { template <class T> void swap(T& a, T& b) noexcept(see below); // この関数から、要素に対し、上の関数をよべばよいのでは? template <class T, size_t N> void swap(T(&a)[N], T(&b)[N]) noexcept(noexcept(swap(*a, *b))); // C++11 // この関数はなぜ必要なのでしょうか。 template <class T, class Allocator> void swap(vector<T, Allocator>& x, vector<T, Allocator>& y); // ほかにも、std::arrayやstd::pairにもswapがある } コメント投稿だと、コードがきれいに貼れず、タブが消えてしまって見づらいですね。
Chironian

2016/03/19 12:34

std::vectorを与えた場合、template <class T, size_t N> void swap(T(&a)[N], T(&b)[N])にはマッチしませんよ。配列の参照を受取る関数テンプレート書いたことありますが、このような記述をすることで、コンテナを受取るものと別関数にすることができました。 たぶん、規格書の14.8.2.5 Deducing template arguments from a typeに書いてあります。 template <class T, class Allocator> void swap(vector<T, Allocator>& x, vector<T, Allocator>& y); は、std::vectorの各要素に対してswap()を呼ぶためにあると思います。 std::arrayやstd::pairもそうなのだろうと思います。 > コメント投稿だと、コードがきれいに貼れず、タブが消えてしまって見づらいですね。 ですよね。HTML系って行頭の空白を無視するので素人にはなかなかハードです。
yohhoy

2016/03/19 12:51

std::swap()関数が一部のコンテナで特殊化されているのは、より「例外安全」で「効率の良いswap実装」を提供するためですよ。 例えばstd::vectorであれば内部バッファを指すポインタ等をswapするだけでよく、要素毎のswapよりも高速です。また要素型によらず、例外安全(例外送出しない)な実装が可能です。
Chironian

2016/03/19 12:55

yohhoyさん。 あ、なるほど。言われてみればその通りですね。 それにcatsforepawさんが回答している通り、要素数が異なる時、要素ごとのswapはできないです。 訂正ありがとうです。
JADEN

2016/03/19 12:59 編集

書いている間に、コメントをいただいたみたいで、yohhoyさんの回答の直前に位置するコメントです。 アンジャッシュ状態になってしまっていますね(笑) なぜ、以下のコードの様な実装ではないのか疑問に思っています。 #include <vector> #include <iostream> template <typename type> void SWAP(type& a, type& b) { std::cout << "SWAP(type& a, type& b)" << std::endl; } template <typename type, int size> void SWAP(type (&a)[size], type (&b)[size]) { std::cout << "SWAP(type (&a)[size], type (&b)[size])" << std::endl; for(int i = 0; i < size; i++) { // 実際のswapでは、上のSWAPに相当するswapを呼ばず、 // void swap(vector<T, Allocator>& x, vector<T, Allocator>& y);を呼ぶ SWAP(a[i], b[i]); } } int main() { std::vector<int> v[2] = {{0, 1}, {2, 3}}; // 上のSWAPが呼ばれる SWAP(v[0], v[1]); // 下のSWAPが呼ばれ、その中で上のSWAPを呼ぶ SWAP(v, v); // そのため、void swap(vector<T, Allocator>& x, vector<T, Allocator>& y);を実装する必要はないのでは? }
Chironian

2016/03/19 13:11

名前空間を除き、utilityもそのような実装になっているように思います。 std::vector<int>のネイティブ配列をswapに渡せば、utilityのswap(配列版)が呼ばれる筈です。 void swap(vector<T, Allocator>& x, vector<T, Allocator>& y);はstd::vector<>を受け取ります。std::vector<>の配列は受け取れません。 JADENさんのソースの中で、vector<int>の中身を表示してみると分かりやすいと思います。
Chironian

2016/03/19 13:33 編集

ああ、ごめんなさい。やっと理解しました。 std::vector<>の配列をswapに渡して、swap(std::vector<>)を呼ばせたくないのですか? たぶんできないような気がしますが、そもそもその必要性が良く分かりません。 --- 【更に追記】 結局、utilityのstd::swap(値版)で十分なのはずなのに何故コンテナ専用のswapがあるのか?という質問ですね? > std::swap()関数が一部のコンテナで特殊化されているのは、より「例外安全」で「効率の良いswap実装」を提供するためですよ。 yohhoyさんのこのフォローでFAのように感じます。
JADEN

2016/03/19 13:50 編集

呼ばせたくないといいますか、私の書いたコードで言うと、 template <typename type> void SWAP(type& a, type& b) と template <typename type, int size> void SWAP(type (&a)[size], type (&b)[size]) だけで事足りるので、 void swap(vector<T, Allocator>& x, vector<T, Allocator>& y); の様なものをなぜ定義する必要があるのか、良く分かりません。 【更に追記】の部分をみていませんでした。 はい、そういう質問です。 その効率の良いswapは、ムーブコンストラクタやムーブ代入演算ではできないのでしょうか? 例えば、std::vectorの内部配列のアドレスを保持しているポインタを交換する処理は、ムーブコンストラクタやムーブ代入演算を用いてutilityの値版swapでもできる気がします。
Chironian

2016/03/19 15:18 編集

具体的な部分は把握していませんが、moveを使ってswapするより、直接swapした方が内部構造と最終目的の両方が分かっている分、より効率の高いプログラムは作れるだろうと思います。 これ以上の話は私ではもうお手上げです。 ところで、swap(コンテナ版)の必要性を問いたいのに対して、swap(配列版)から入るとは凄いミスリードですね? 流石にわざとではないですよね?
JADEN

2016/03/19 16:32 編集

>> 流石にわざとではないですよね? わざとではないです。 回答には感謝していますが、根拠のない因縁をつけられるようであれば、それなりの対応をします。
Chironian

2016/03/20 02:27

今回、JADENさんはミスリードをしました。 しかし、JADENさんのコメントからミスをしたという思いが全く読み取れません。 ミスでないのなら意図的なミスリードですので、念のため確認させて頂きました。 私はJADENさんのミスリードに振り回されましたので、この程度の確認は許容頂きたいところです。
guest

0

配列版の処理において、ループで非配列版のswapを呼び出す処理ではいけないのでしょうか。

二つの配列のサイズが同じとは限らないので、ループで各要素を交換するというやり方はできません。コンテナ自体がコピー可能なので、やるなら要素単位ではなく丸ごとswapに渡せば良いです。

この様にすれば、各コンテナでswapを実装する必要がなくなる気がします。

コンテナが保持しているデータを交換するよりも、内部で確保した領域のポインタを交換する方が遙かに高速です。そのような特殊な処理をするために専用のswapが必要です。

投稿2016/03/19 08:47

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

catsforepaw

2016/03/19 09:03

「コンテナ」に反応してリンク先をよく見ていませんでした。ネイティブな配列のことみたいですね。ちょっと見当違いの回答だったかもしれません。無視してください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問