-1

質問は非常に単純です、それは一般的に安全な静的キャスト(または他のキャスト)から

std::vector< Foo >

std::vector< const Foo >

バイナリに関しては、ネイティブタイプが異なる理由がわかりません。結局のところ、これconstは要素のサイズに影響を与えない言語の制約であるため、

僕にできる

std::vector< const Foo >& someFunc()
{
  std::vector< Foo >& ref = ...
  return *reinterpret_cast<std::vector< const Foo >*>(& ref);
}

これが誰かのボートを沈めることを心配しないでください?またはこれは一般的に安全ではありませんか?

4

1 に答える 1

2

今のところstd::vectorと言ったことを無視し、他のあまり明確に定義されていないベクトルの実装があるふりをします。TT constがまったく異なるためではなく、C ++言語が許可vector<T>し、vector<T const>まったく異なる方法に特化しているため、コードは技術的に安全ではありません。次のコードを検討してください。

#include <iostream>

template <class T>
struct vector {
    T* start_;
    T* end_;
    T* cap_end_;
};

template <class T>
struct vector<T const> {
    bool gotcha_;
    T* start_;
    T* end_;
    T* cap_end_;
};

struct foo { };

int
main()
{
    std::cout
        << sizeof(vector<foo>) << '\n'
        << sizeof(vector<foo const>) << '\n'
        ;
}

あなたの人生を悲惨にする可能性のある他のもっと有害な変化があることに注意してください。メンバーが並べ替えられる次のようなもの:

#include <iostream>

template <class T>
struct vector {
    T* start_;
    T* end_;
    T* cap_end_;
};

template <class T>
struct vector<T const> {
    T* end_;
    T* cap_end_;
    T* start_;
};

template <class T>
long size(vector<T> const& v)
{
    return v.end_ - v.start_;
}

struct foo { };

int
main()
{
    vector<foo> v;
    v.start_ = new foo[10];
    v.end_ = v.start_ + 1;
    v.cap_end_ = v.start_ + 10;


    std::cout
        << size(v) << '\n'
        << size(*reinterpret_cast<vector<foo const>*>(&v)) << '\n'
        ;

    return 0;
}

std :: vectorについては、標準ライブラリの仕様の詳細に精通していないため、そのような特殊化が準拠しているかどうかを知ることができません。おそらく、標準に精通している誰かがコメントすることができます。

テンプレート化されたクラスをより一般的な専門分野にキャストすることに答えて私が言ったことのいくつかは、この問題を説明するのに役立つかもしれないことに注意してください。

特殊化の検出に関する質問に対処するために、クラスの特殊化を使用せずに非メンバー関数をオーバーロードすることでコードを安全でなくする方法がありますが、それをどのように検出するかはわかりません。次のように:

#include <iostream>

template <class T>
struct vector {
    T* start_;
    T* end_;
    T* cap_end_;
};


template <class T>
void init(vector<T>& v, size_t sz, size_t cap)
{
    v.start_ = new T[cap];
    v.end_ = v.start_ + sz;
    v.cap_end_ = v.start_ + cap;
}

template <class T>
void init(vector<T const>& v, size_t sz, size_t cap)
{
    v.end_ = new T const[cap];
    v.cap_end_ = v.end_ + sz;
    v.start_ = v.end_ + cap;
}

template <class T>
long size(vector<T>& v)
{
    return v.end_ - v.start_;
}

template <class T>
long size(vector<T const>& v)
{
    return v.cap_end_ - v.end_;
}

struct foo { };

int
main()
{
    vector<foo const> v;
    init(v, 1, 10);

    std::cout
        << size(v) << '\n'
        << size(*reinterpret_cast<vector<foo>*>(&v)) << '\n'
        ;
}

悪い知らせで十分です。良いニュースは、一般的なインターフェイスを備えた既存のオブジェクトを取得し、そのオブジェクトで実行できることを制限または調整したい場合、それを行うための簡単で安全でわかりやすい方法がいくつかあることです。std :: stack http://www.sgi.com/tech/stl/stack.htmlをご覧になるか、C++のプロキシクラスとはhttps://stackoverflow.com/a/994925/453436に回答 してください。

于 2013-01-09T04:50:34.687 に答える