コピーアンドスワップのイディオムとは何ですか?

2081
GManNickG 2010-07-19 22:42.

このイディオムとは何ですか?いつ使用する必要がありますか?どの問題を解決しますか?C ++ 11を使用すると、イディオムは変わりますか?

多くの場所で言及されていますが、「それは何ですか」という単一の質問と回答がなかったので、ここにあります。これは以前に言及された場所の部分的なリストです:

  • お気に入りのC ++コーディングスタイルのイディオムは何ですか:コピースワップ
  • コピーコンストラクタと= C ++での演算子のオーバーロード:一般的な関数は可能ですか?
  • コピーの省略とは何ですか、そしてそれがコピーとスワップのイディオムをどのように最適化するか
  • C ++:オブジェクトの配列を動的に割り当てますか?

5 answers

2252
GManNickG 2010-07-19 22:43.

概要概要

なぜコピーアンドスワップのイディオムが必要なのですか?

リソース(スマートポインターなどのラッパー)を管理するクラスは、The BigThreeを実装する必要があります。コピーコンストラクタとデストラクタの目標と実装は簡単ですが、コピー割り当て演算子は間違いなく最も微妙で難しいものです。それはどのように行われるべきですか?どのような落とし穴を避ける必要がありますか?

コピーおよびスワップイディオムはソリューションであり、そしてエレガントに二つのことを達成するために、代入演算子を支援:回避コードの重複を、そして提供する強力な例外保証を。

それはどのように機能しますか?

概念的には、コピーコンストラクターの機能を使用してデータのローカルコピーを作成し、コピーされたデータをswap関数で取得して、古いデータを新しいデータと交換することで機能します。次に、一時コピーが破棄され、古いデータが一緒に取得されます。新しいデータのコピーが残っています。

コピーアンドスワップのイディオムを使用するには、3つのものが必要です。動作するコピーコンストラクタ、動作するデストラクタ(どちらもラッパーの基礎であるため、とにかく完全である必要があります)、およびswap関数です。

スワップ関数は、クラスの2つのオブジェクト、メンバーをメンバーにスワップする非スロー関数です。std::swap独自のものを提供する代わりに使用したくなるかもしれませんが、これは不可能です。std::swap実装内でcopy-constructorとcopy-assignment演算子を使用し、最終的にはそれ自体の観点から代入演算子を定義しようとしています。

(それだけでなく、への修飾されていない呼び出しswapは、カスタムスワップ演算子を使用し、必要なクラスの不要な構築と破棄をスキップしstd::swapます。)


詳細な説明

目標

具体的なケースを考えてみましょう。他の方法では役に立たないクラスで、動的配列を管理したいと思います。まず、動作するコンストラクタ、コピーコンストラクタ、およびデストラクタから始めます。

#include <algorithm> // std::copy
#include <cstddef> // std::size_t

class dumb_array
{
public:
    // (default) constructor
    dumb_array(std::size_t size = 0)
        : mSize(size),
          mArray(mSize ? new int[mSize]() : nullptr)
    {
    }

    // copy-constructor
    dumb_array(const dumb_array& other)
        : mSize(other.mSize),
          mArray(mSize ? new int[mSize] : nullptr),
    {
        // note that this is non-throwing, because of the data
        // types being used; more attention to detail with regards
        // to exceptions must be given in a more general case, however
        std::copy(other.mArray, other.mArray + mSize, mArray);
    }

    // destructor
    ~dumb_array()
    {
        delete [] mArray;
    }

private:
    std::size_t mSize;
    int* mArray;
};

このクラスは配列をほぼ正常に管理しますがoperator=、正しく機能する必要があります。

失敗した解決策

単純な実装がどのように見えるかを次に示します。

// the hard part
dumb_array& operator=(const dumb_array& other)
{
    if (this != &other) // (1)
    {
        // get rid of the old data...
        delete [] mArray; // (2)
        mArray = nullptr; // (2) *(see footnote for rationale)

        // ...and put in the new
        mSize = other.mSize; // (3)
        mArray = mSize ? new int[mSize] : nullptr; // (3)
        std::copy(other.mArray, other.mArray + mSize, mArray); // (3)
    }

    return *this;
}

そして、私たちは終了したと言います。これにより、リークなしでアレイを管理できるようになりました。ただし、コード内で(n)。として順番にマークされている3つの問題があります。

  1. 1つ目は自己割り当てテストです。このチェックには2つの目的があります。自己割り当てで不要なコードを実行するのを防ぐ簡単な方法であり、微妙なバグ(配列を削除してコピーを試みるなど)から保護します。しかし、他のすべての場合、それは単にプログラムの速度を低下させ、コード内のノイズとして機能するだけです。自己割り当てが発生することはめったにないため、ほとんどの場合、このチェックは無駄です。オペレーターがそれなしで適切に働くことができればより良いでしょう。

  2. 2つ目は、基本的な例外保証のみを提供することです。場合はnew int[mSize]失敗し、*this変更されています。(つまり、サイズが間違っていて、データが失われています!)強力な例外保証を行うには、次のようなものである必要があります。

    dumb_array& operator=(const dumb_array& other)
    {
        if (this != &other) // (1)
        {
            // get the new data ready before we replace the old
            std::size_t newSize = other.mSize;
            int* newArray = newSize ? new int[newSize]() : nullptr; // (3)
            std::copy(other.mArray, other.mArray + newSize, newArray); // (3)
    
            // replace the old data (all are non-throwing)
            delete [] mArray;
            mSize = newSize;
            mArray = newArray;
        }
    
        return *this;
    }
    
  3. コードが拡張されました!これは、3番目の問題であるコードの重複につながります。私たちの代入演算子は、すでに他の場所で書いたすべてのコードを効果的に複製しますが、それはひどいことです。

私たちの場合、そのコアは2行(割り当てとコピー)だけですが、より複雑なリソースでは、このコードの膨張は非常に面倒な場合があります。私たちは決して繰り返さないように努めるべきです。

(1つのリソースを正しく管理するためにこれだけのコードが必要な場合、クラスが複数のリソースを管理する場合はどうなるでしょうか?これは有効な懸念事項のように思われるかもしれませんが、実際には重要なtry/catch句が必要ですが、これは-問題。これは、クラスが1つのリソースのみを管理する必要があるためです!)

成功したソリューション

前述のように、コピーアンドスワップのイディオムはこれらすべての問題を修正します。しかし、現時点では、swap関数という1つを除いてすべての要件があります。Rule of Threeは、コピーコンストラクタ、代入演算子、およびデストラクタの存在を正常に伴いますが、実際には「ビッグスリーアンドハーフ」と呼ばれる必要があります。クラスがリソースを管理するときはいつでも、swap関数を提供することも理にかなっています。 。

クラスにスワップ機能を追加する必要があります。これは次のように行います†:

class dumb_array
{
public:
    // ...

    friend void swap(dumb_array& first, dumb_array& second) // nothrow
    {
        // enable ADL (not necessary in our case, but good practice)
        using std::swap;

        // by swapping the members of two objects,
        // the two objects are effectively swapped
        swap(first.mSize, second.mSize);
        swap(first.mArray, second.mArray);
    }

    // ...
};

(ここで説明する理由があるpublic friend swap。)今、我々は交換することができないだけdumb_arrayのを、一般的にはスワップは、より効率的にすることができます。配列全体を割り当ててコピーするのではなく、ポインタとサイズを交換するだけです。機能性と効率性におけるこのボーナスとは別に、コピーアンドスワップイディオムを実装する準備が整いました。

さらに面倒なことをしなくても、代入演算子は次のとおりです。

dumb_array& operator=(dumb_array other) // (1)
{
    swap(*this, other); // (2)

    return *this;
}

以上です!一挙に、3つの問題すべてに一度にエレガントに取り組むことができます。

なぜそれが機能するのですか?

最初に重要な選択に気づきます。パラメータ引数は値によって取得されます。次のことも同じように簡単に実行できますが(実際、イディオムの多くの単純な実装では実行できます)。

dumb_array& operator=(const dumb_array& other)
{
    dumb_array temp(other);
    swap(*this, temp);

    return *this;
}

重要な最適化の機会を失います。それだけでなく、この選択は、後で説明するC ++ 11では重要です。(一般的に、非常に役立つガイドラインは次のとおりです。関数内で何かのコピーを作成する場合は、コンパイラーにパラメーターリストで作成させます。‡)

いずれにせよ、リソースを取得するこの方法は、コードの重複を排除するための鍵です。コピーコンストラクターからのコードを使用してコピーを作成することができ、それを少しも繰り返す必要はありません。コピーが作成されたので、交換する準備が整いました。

関数に入ると、すべての新しいデータがすでに割り当てられ、コピーされ、使用できる状態になっていることを確認してください。これは、無料で強力な例外保証を提供するものです。コピーの構築が失敗した場合、関数に入ることができないため、の状態を変更することはできません*this。(強力な例外保証のために以前に手動で行ったこと、コンパイラーが現在私たちのために行っています;どのように親切です。)

この時点で、私たちはホームフリーswapです。なぜなら、投げていないからです。現在のデータをコピーされたデータと交換し、状態を安全に変更すると、古いデータが一時データに入れられます。関数が戻ると、古いデータが解放されます。(パラメーターのスコープが終了し、そのデストラクタが呼び出されたとき。)

イディオムはコードを繰り返さないため、オペレーター内にバグを導入することはできません。これは、自己割り当てチェックの必要性がなくなり、の単一の均一な実装が可能になることを意味することに注意してくださいoperator=。(さらに、非自己割り当てに対するパフォーマンスのペナルティはなくなりました。)

そして、それがコピーアンドスワップのイディオムです。

C ++ 11はどうですか?

C ++の次のバージョンであるC ++ 11は、リソースの管理方法に1つの非常に重要な変更を加えます。3つのルールが4つのルール(および半分)になりました。どうして?リソースをコピー構築できる必要があるだけでなく、リソースを移動構築する必要もあります。

私たちにとって幸運なことに、これは簡単です。

class dumb_array
{
public:
    // ...

    // move constructor
    dumb_array(dumb_array&& other) noexcept ††
        : dumb_array() // initialize via default constructor, C++11 only
    {
        swap(*this, other);
    }

    // ...
};

何が起きてる?移動構築の目標を思い出してください。クラスの別のインスタンスからリソースを取得し、割り当て可能で破壊可能であることが保証された状態のままにします。

したがって、私たちが行ったことは単純です。デフォルトのコンストラクター(C ++ 11機能)を介して初期化し、次にother;と交換します。クラスのデフォルトで構築されたインスタンスを安全に割り当てて破棄otherできることがわかっているので、交換後に同じことができるようになります。

(一部のコンパイラーはコンストラクター委任をサポートしていないことに注意してください。この場合、手動でデフォルトでクラスを作成する必要があります。これは残念ながら簡単な作業です。)

なぜそれが機能するのですか?

それがクラスに加える必要がある唯一の変更ですが、なぜそれが機能するのですか?パラメータを参照ではなく値にするという、これまでになく重要な決定を覚えておいてください。

dumb_array& operator=(dumb_array other); // (1)

これで、otherが右辺値で初期化されている場合、move-constructedになります。完璧です。C ++ 03で引数を値で取得してコピーコンストラクター機能を再利用できるのと同じように、C ++ 11でも適切な場合にmoveコンストラクターが自動的に選択されます。(そしてもちろん、以前にリンクされた記事で述べたように、値のコピー/移動は単に完全に省略されるかもしれません。)

そして、これでコピーアンドスワップのイディオムは終わりです。


脚注

*なぜmArraynullに設定するのですか?演算子のコードがさらにスローされると、のデストラクタdumb_arrayが呼び出される可能性があるためです。nullに設定せずにそれが発生した場合は、すでに削除されているメモリを削除しようとします。nullの削除は操作なしであるため、nullに設定することでこれを回避します。

std::swap私たちが自分のタイプに特化しswapたり、フリー関数swapと一緒にクラス内を提供したりする必要があるという主張は他にもあります。しかし、これはすべて不要です。適切に使用swapする場合は、修飾されていない呼び出しを介して行われ、関数は次のようになります。ADLを通じて見つかりました。1つの機能で十分です。

‡理由は単純です。自分自身にリソースを取得したら、必要な場所にリソースを交換または移動(C ++ 11)することができます。また、パラメータリストにコピーを作成することで、最適化を最大化できます。

††移動コンストラクターは通常noexcept、である必要があります。そうでないstd::vector場合、移動が意味をなす場合でも、一部のコード(サイズ変更ロジックなど)はコピーコンストラクターを使用します。もちろん、内部のコードが例外をスローしない場合にのみ、noexceptとマークしてください。

288
sbi 2010-07-19 22:55.

割り当ては、基本的に2つのステップです。オブジェクトの古い状態破棄することと、他のオブジェクトの状態のコピーとして新しい状態を構築することです。

基本的に、これはデストラクタコピーコンストラクタが行うことなので、最初のアイデアは作業をそれらに委任することです。ただし、破壊は失敗してはならないので、建設は失敗しないかもしれませんが、実際には逆の方法で実行したいと思います最初に建設部分実行し、それが成功した場合は破壊部分を実行します。コピーアンドスワップのイディオムは、まさにそれを行う方法です。最初にクラスのコピーコンストラクターを呼び出して一時オブジェクトを作成し、次にそのデータを一時オブジェクトと交換してから、一時オブジェクトのデストラクタに古い状態を破棄させます。失敗することはないはずな
のでswap()、失敗する可能性があるのはコピー構築だけです。これが最初に実行され、失敗した場合、ターゲットオブジェクトで何も変更されません。

洗練された形式では、コピーアンドスワップは、代入演算子の(非参照)パラメーターを初期化することによってコピーを実行することによって実装されます。

T& operator=(T tmp)
{
    this->swap(tmp);
    return *this;
}
44
Tony Delroy 2014-03-07 04:51.

すでにいくつかの良い答えがあります。私はに、彼らが欠けていると思うものに焦点を当てます-コピーアンドスワップイディオムによる「短所」の説明...。

コピーアンドスワップのイディオムとは何ですか?

スワップ関数の観点から代入演算子を実装する方法:

X& operator=(X rhs)
{
    swap(rhs);
    return *this;
}

基本的な考え方は次のとおりです。

  • オブジェクトへの割り当てで最もエラーが発生しやすい部分は、新しい状態に必要なリソース(メモリ、記述子など)を確実に取得することです。

  • 新しい値のコピーが作成された場合、オブジェクトの現在の状態を変更する前に(つまり*this)取得を試みることができます。そのため、参照ではなく値によってrhs受け入れられます(つまりコピーされます)。

  • ローカルコピーの状態を交換rhsして*thisいる通常は潜在的な障害/例外なしで行うことは比較的容易で、ローカルコピー与えられているオブジェクトの限り、単に実行するためにデストラクタの状態フィットを必要とする(後から任意の特定の状態を必要としない移動から> = C ++ 11)

いつ使用する必要がありますか?(どの問題を解決します[/ create]?)

  • 例外をスローする割り当ての影響を受けない割り当て先オブジェクトが必要な場合swap、強力な例外保証を備えた、または記述できる、理想的には失敗しないものを想定しますthrow/..†

  • (より単純な)コピーコンストラクターswapとデストラクタ関数の観点から代入演算子を定義するための、クリーンで理解しやすい堅牢な方法が必要な場合。

    • コピーアンドスワップとして行われる自己割り当ては、見過ごされがちなエッジケースを回避します。‡

  • 割り当て中に追加の一時オブジェクトを使用することによってパフォーマンスが低下したり、リソース使用量が一時的に高くなったりすることが、アプリケーションにとって重要でない場合。⁂

swapスロー:オブジェクトがポインターによって追跡するデータメンバーを確実にスワップすることは一般に可能ですが、スローフリースワップがない、またはスワッピングX tmp = lhs; lhs = rhs; rhs = tmp;をコピー構築または割り当てとして実装する必要がある非ポインターデータメンバースローする可能性がありますが、一部のデータメンバーを交換したままにして、他のメンバーを交換しないまま失敗する可能性があります。std::stringJamesが別の答えについてコメントしているように、この可能性はC ++ 03にも当てはまります。

@wilhelmtell:C ++ 03では、std :: string :: swap(std :: swapによって呼び出される)によってスローされる可能性のある例外については言及されていません。C ++ 0xでは、std :: string :: swapはnoexceptであり、例外をスローしてはなりません。– James McNellis 2010年12月22日15:24


‡個別のオブジェクトから割り当てるときに正常と思われる代入演算子の実装は、自己代入で簡単に失敗する可能性があります。クライアントコードが自己割り当てを試みることは想像できないように思われるかもしれませんが、コンテナでのアルゴ操作中に比較的簡単に発生する可能性がありx = f(x);ます。コードfは(おそらく一部の#ifdefブランチのみ)マクロala#define f(x) xまたは関数がへの参照を返すか、xさらには(おそらく非効率的ですが簡潔です)のようなコードx = c1 ? x * 2 : c2 ? x / 2 : x;。例えば:

struct X
{
    T* p_;
    size_t size_;
    X& operator=(const X& rhs)
    {
        delete[] p_;  // OUCH!
        p_ = new T[size_ = rhs.size_];
        std::copy(p_, rhs.p_, rhs.p_ + rhs.size_);
    }
    ...
};

自己割り当てでは、上記のコードdeleteは、新しく割り当てられたヒープ領域をx.p_;ポイントp_し、その中の初期化されていないデータ(未定義の振る舞い)を読み取ろうとします。それがあまり奇妙なことをしない場合はcopy、すべてのジャストに自己割り当てを試みます-破壊された「T」!


⁂コピーアンドスワップイディオムは、余分な一時的なものを使用するため、非効率または制限をもたらす可能性があります(オペレーターのパラメーターがコピー構築されている場合)。

struct Client
{
    IP_Address ip_address_;
    int socket_;
    X(const X& rhs)
      : ip_address_(rhs.ip_address_), socket_(connect(rhs.ip_address_))
    { }
};

ここで、手書きはがすでに同じサーバーに接続されているClient::operator=かどうかをチェックする可能性があり*thisますrhs(おそらく、有用な場合は「リセット」コードを送信します)が、コピーアンドスワップアプローチは、開くように記述されている可能性が高いコピーコンストラクターを呼び出します次に、別のソケット接続を閉じて、元のソケット接続を閉じます。これは、単純なインプロセス変数コピーではなく、リモートネットワークの相互作用を意味するだけでなく、ソケットリソースまたは接続に対してクライアントまたはサーバーの制限に違反する可能性があります。(もちろん、このクラスにはかなり恐ろしいインターフェースがありますが、それは別の問題です; -P)。

25
Oleksiy 2013-09-04 18:50.

この回答は、上記の回答への追加とわずかな変更のようなものです。

Visual Studioの一部のバージョン(および場合によっては他のコンパイラー)には、本当に煩わしくて意味をなさないバグがあります。したがって、swap関数を次のように宣言/定義すると、次のようになります。

friend void swap(A& first, A& second) {

    std::swap(first.size, second.size);
    std::swap(first.arr, second.arr);

}

...swap関数を呼び出すと、コンパイラはあなたに怒鳴ります:

これは、friend呼び出される関数とthisパラメーターとして渡されるオブジェクトと関係があります。


これを回避する方法は、friendキーワードを使用せず、swap関数を再定義することです。

void swap(A& other) {

    std::swap(size, other.size);
    std::swap(arr, other.arr);

}

今回は、を呼び出しswapて渡すだけでother、コンパイラを満足させることができます。


結局のところ、2つのオブジェクトを交換するために関数を使用する必要ありませんfriendswap1つのotherオブジェクトをパラメーターとして持つメンバー関数を作成することも同様に理にかなっています。

すでにthisオブジェクトにアクセスできるため、パラメータとして渡すことは技術的に冗長です。

15
Kerrek SB 2014-06-24 22:16.

C ++ 11スタイルのアロケーター対応コンテナーを扱っている場合は、警告を追加したいと思います。スワッピングと割り当てのセマンティクスは微妙に異なります。

具体的には、ステートフルアロケータタイプstd::vector<T, A>であるコンテナについて考えてみAましょう。次の関数を比較します。

void fs(std::vector<T, A> & a, std::vector<T, A> & b)
{ 
    a.swap(b);
    b.clear(); // not important what you do with b
}

void fm(std::vector<T, A> & a, std::vector<T, A> & b)
{
    a = std::move(b);
}

両方の機能の目的fs及びfm提供することですa状態b最初に持っていたし。ただし、隠された質問がありa.get_allocator() != b.get_allocator()ます。答えは:それは異なります。書きましょうAT = std::allocator_traits<A>

  • 場合AT::propagate_on_container_move_assignmentでありstd::true_type、その後fmのアロケータ再割り当てaの値をb.get_allocator()、それ以外の場合はない、そして、a元のアロケータを使用し続けます。その場合、aとのストレージにbは互換性がないため、データ要素を個別に交換する必要があります。

  • 場合AT::propagate_on_container_swapstd::true_typeは、fs予想される形で、データとアロケータの両方を交換します。

  • 場合AT::propagate_on_container_swapstd::false_type、我々は動的なチェックが必要です。

    • の場合a.get_allocator() == b.get_allocator()、2つのコンテナは互換性のあるストレージを使用し、スワッピングは通常の方法で進行します。
    • ただし、の場合a.get_allocator() != b.get_allocator()、プログラムの動作未定義です([container.requirements.general / 8]を参照)。

結果として、コンテナがステートフルアロケータのサポートを開始するとすぐに、C ++ 11ではスワッピングが重要な操作になります。これはやや「高度なユースケース」ですが、移動の最適化は通常、クラスがリソースを管理した後でのみ興味深いものになり、メモリは最も人気のあるリソースの1つであるため、まったくありそうもないことではありません。

Related questions

MORE COOL STUFF

「水曜日」シーズン1の中心には大きなミステリーがあります

「水曜日」シーズン1の中心には大きなミステリーがあります

Netflixの「水曜日」は、典型的な10代のドラマ以上のものであり、実際、シーズン1にはその中心に大きなミステリーがあります.

ボディーランゲージの専門家は、州訪問中にカミラ・パーカー・ボウルズが輝くことを可能にした微妙なケイト・ミドルトンの動きを指摘しています

ボディーランゲージの専門家は、州訪問中にカミラ・パーカー・ボウルズが輝くことを可能にした微妙なケイト・ミドルトンの動きを指摘しています

ケイト・ミドルトンは、州の夕食会と州の訪問中にカミラ・パーカー・ボウルズからスポットライトを奪いたくなかった、と専門家は言う.

一部のファンがハリー・スタイルズとオリビア・ワイルドの「非常に友好的な」休憩が永続的であることを望んでいる理由

一部のファンがハリー・スタイルズとオリビア・ワイルドの「非常に友好的な」休憩が永続的であることを望んでいる理由

一部のファンが、オリビア・ワイルドが彼女とハリー・スタイルズとの間の「難しい」が「非常に友好的」な分割を恒久的にすることを望んでいる理由を見つけてください.

エリザベス女王の死後、ケイト・ミドルトンはまだ「非常に困難な時期」を過ごしている、と王室の専門家が明らかにする 

エリザベス女王の死後、ケイト・ミドルトンはまだ「非常に困難な時期」を過ごしている、と王室の専門家が明らかにする&nbsp;

エリザベス女王の死後、ケイト・ミドルトンが舞台裏で「非常に困難な時期」を過ごしていたと伝えられている理由を調べてください.

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セント ヘレナ島のジェイコブズ ラダーは 699 段の真っ直ぐ上る階段で、頂上に到達すると証明書が発行されるほどの難易度です。

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

Total War:Warhammer:Kotakuレビュー

Total War:Warhammer:Kotakuレビュー

私はこのゲームを嫌う準備ができていました。先週の前に、Total War:Warhammerについての私の考えがありました:それでもここに私は、私の手にある完成品であり、私は変わった男です。

涙の道:軍事化された帝国主義勢力がスタンディングロックキャンプを占領

涙の道:軍事化された帝国主義勢力がスタンディングロックキャンプを占領

スタンディングロックスー族のメンバーと水の保護者は、ノースダコタ州のスタンディングロックにあるオセティサコウィンキャンプを去ります。(Twitter経由のCNNスクリーンショット)火と煙がスカイラインを覆い、スタンディングロックスー族のメンバーと水の保護者が、聖なるものを守りながら建てた家、オセティサコウィン(セブンカウンシルファイアーズ)キャンプから行進し、太鼓を打ち、歌い、祈りました。ダコタアクセスパイプラインとしても知られる「ブラックスネーク」からの土地。

シアーズとKマートはイヴァンカ・トランプの商品を自分たちで取り除いています

シアーズとKマートはイヴァンカ・トランプの商品を自分たちで取り除いています

写真:APシアーズとKマートは、イヴァンカ・トランプのトランプホームアイテムのコレクションも、誰も購入したくないために削除しました。シアーズとKマートの両方の親会社であるシアーズホールディングスは、土曜日のABCニュースへの声明で、彼らが気にかけていると辛抱強く説明しましたトランプラインを売り続けるにはお金を稼ぐことについてあまりにも多く。

ポテトチップスでたった10分でスペインのトルティーヤを作る

ポテトチップスでたった10分でスペインのトルティーヤを作る

伝統的なスペインのトルティーヤは通常、オリーブオイルで柔らかくなるまで調理されたポテトから始まります(30分以上かかる場合があります)が、ケトルで調理されたポテトチップスの助けを借りてわずか10分でテーブルに置くことができます。上のビデオはすべてがバラバラにならないように裏返す方法を含め、レシピ全体を説明しますが、必要なのは4〜5個の卵と3カップのケトルチップスだけです。

ケイト・ミドルトンとウィリアム王子は、彼らが子供たちと行っているスパイをテーマにした活動を共有しています

ケイト・ミドルトンとウィリアム王子は、彼らが子供たちと行っているスパイをテーマにした活動を共有しています

ケイト・ミドルトンとウィリアム王子は、子供向けのパズルの本の序文を書き、ジョージ王子、シャーロット王女、ルイ王子と一緒にテキストを読むと述べた.

事故で押しつぶされたスイカは、動物を喜ばせ水分補給するために野生生物保護団体に寄付されました

事故で押しつぶされたスイカは、動物を喜ばせ水分補給するために野生生物保護団体に寄付されました

Yak's Produce は、数十個のつぶれたメロンを野生動物のリハビリ専門家であるレスリー グリーンと彼女のルイジアナ州の救助施設で暮らす 42 匹の動物に寄付しました。

デミ・ロヴァートは、新しいミュージシャンのボーイフレンドと「幸せで健康的な関係」にあります: ソース

デミ・ロヴァートは、新しいミュージシャンのボーイフレンドと「幸せで健康的な関係」にあります: ソース

8 枚目のスタジオ アルバムのリリースに向けて準備を進めているデミ ロヴァートは、「スーパー グレート ガイ」と付き合っている、と情報筋は PEOPLE に確認しています。

Plathville の Kim と Olivia Plath が数年ぶりに言葉を交わすことへようこそ

Plathville の Kim と Olivia Plath が数年ぶりに言葉を交わすことへようこそ

イーサン プラスの誕生日のお祝いは、TLC のウェルカム トゥ プラスビルのシーズン 4 のフィナーレで、戦争中の母親のキム プラスと妻のオリビア プラスを結びつけました。

仕事の生産性を高める 8 つのシンプルなホーム オフィスのセットアップのアイデア

仕事の生産性を高める 8 つのシンプルなホーム オフィスのセットアップのアイデア

ホームオフィスのセットアップ術を極めよう!AppExert の開発者は、家族全員が一緒にいる場合でも、在宅勤務の技術を習得しています。祖父や曽祖父が共同家族で暮らしていた頃の記憶がよみがえりました。

2022 年、私たちのデジタル ライフはどこで終わり、「リアル ライフ」はどこから始まるのでしょうか?

20 年前のタイムトラベラーでさえ、日常生活におけるデジタルおよびインターネットベースのサービスの重要性に驚くことでしょう。MySpace、eBay、Napster などのプラットフォームは、高速化に焦点を合わせた世界がどのようなものになるかを示してくれました。

ニューロマーケティングの秘密科学

ニューロマーケティングの秘密科学

マーケティング担当者が人間の欲望を操作するために使用する、最先端の (気味が悪いと言う人もいます) メソッドを探ります。カートをいっぱいにして 3 桁の領収書を持って店を出る前に、ほんの数点の商品を買いに行ったことはありませんか? あなたは一人じゃない。

地理情報システムの日: GIS 開発者として学ぶべき最高の技術スタック

地理情報システムの日: GIS 開発者として学ぶべき最高の技術スタック

私たちが住んでいる世界を確実に理解するには、データが必要です。ただし、空間参照がない場合、このデータは地理的コンテキストがないと役に立たなくなる可能性があります。

Language