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

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

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

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

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

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

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

グッドジョブ、ESPN

グッドジョブ、ESPN

今日のホワイトハウスの記者会見で、報道官のサラ・ハッカビー・サンダースは、スポーツセンターのホストであるイェメル・ヒルのドナルド・トランプに関する最近のツイートについてコメントするよう求められ、大統領と彼の政策を白人至上主義者として説明した。ヒルは彼女のつぶやきのためにESPNによって公に叱責されました。

アマゾンからのこのレミントンツールセールで髪を整える、スタイルを整える、乾かす、または取り除く

アマゾンからのこのレミントンツールセールで髪を整える、スタイルを整える、乾かす、または取り除く

基本的に頭のあらゆる部分から髪の毛を整えたり、ブロードライしたり、まっすぐにしたり、脱毛したりする必要がある場合は、このレミントンゴールドボックスが最適です。今日だけ、Amazonは、すでに人気のあるShortcut Pro Self-HaircutKitやPearlPro Ceramic Flat Ironのように、グルーミングをはるかに簡単にするヘアツールをマークダウンしています。

カナダの元桂冠詩人が、史上最高の文化の盗用でトゥパックとマヤアンジェロウから盗んだ

カナダの元桂冠詩人が、史上最高の文化の盗用でトゥパックとマヤアンジェロウから盗んだ

トゥパックシャクール(ティムモーゼンフェルダー/ゲッティイメージズ); マヤアンジェロウ(マーティンゴッドウィン/ゲッティイメージズ)移動、テイラースウィフト。ケンドールとカイリーは、必要な数の座席を持っています。

テスラは、ハリケーンイルマによる避難を容易にするために、フロリダでの車両の範囲を拡大しています

テスラは、ハリケーンイルマによる避難を容易にするために、フロリダでの車両の範囲を拡大しています

写真:Tesla Motorsフロリダに住んでいて、Tesla Model S、Model X 60、またはModel 60Dを使用している場合、車の自律性は50 km(約30マイル)高くなります。これは失敗ではなく、ハリケーンイルマによる避難作業を容易にするために会社自身が命じた自治権の一時的な延長です。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

投資ノート:Bioscout AU$300万シード

投資ノート:Bioscout AU$300万シード

Bioscoutは、農家を運転席に置くという使命を負っています。Artesian(GrainInnovate)やUniseedと並んで、最新のシードラウンドでチームを支援できることをうれしく思います。問題真菌症による重大な作物の損失は、農民にとって試練であることが証明されています。

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

遠隔医療は、パンデミック後の時代では新しいものではなく、時代遅れの分野でもありません。しかし、業界を詳しく見ると、需要と供給の強力な持続可能性と、米国で絶え間ない革命となる強力な潜在的成長曲線を示しています。

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

2021年は、世界的なベンチャーキャピタル(VC)の資金調達にとって記録的な年でした。DealStreetAsiaによると、東南アジアも例外ではなく、この地域では年間で記録的な25の新しいユニコーンが採掘されました。

ムーアの法則を超えて

ムーアの法則を超えて

計算に対する私たちの欲求とムーアの法則が提供できるものとの間には、指数関数的に増大するギャップがあります。私たちの文明は計算に基づいています—建築と想像力の現在の限界を超える技術を見つけなければなりません。

Language