Как генерировать предупреждение компилятора / ошибка когда нарезанный объект

Предоставление ОЗУ всего 768 МБ работает над окном и устраняет проблему. Ниже приведена ссылка stackoverflow, откуда я получил способ заставить ее работать.

https://stackoverflow.com/a/16850152/2926806

17
задан Baiyan Huang 7 March 2009 в 11:19
поделиться

8 ответов

Если можно изменить базовый класс, Вы могли бы сделать что-то как:

class Base
{
public:
// not implemented will cause a link error
    Base(const Derived &d);
    const Base &operator=(const Derived &rhs);
};

В зависимости от Вашего компилятора, который должен получить Вас единица перевода и возможно функция, где разрезание происходит.

16
ответ дан 30 November 2019 в 12:20
поделиться

Как изменение ответ Andrew Khosravian , я предложу использовать шаблонных конструкторов копии и операторы присваивания. Таким образом, Вы не должны знать все производные классы данного базового класса для охраны того базового класса против разрезания:

class Base
{
private:   // To force a compile error for non-friends (thanks bk1e)
// Not implemented, so will cause a link error for friends
    template<typename T> Base(T const& d);
    template<typename T> Base const& operator=(T const& rhs);

public:
// You now need to provide a copy ctor and assignment operator for Base
    Base(Base const& d) { /* Initialise *this from d */ }
    Base const& operator=(Base const& rhs) { /* Copy d to *this */ }
};

, Хотя это уменьшает необходимый объем работы с этим подходом, все еще необходимо смешать с каждым базовым классом для охраны его. Кроме того, это вызовет проблемы, если будут законные преобразования от Base до SomeOtherClass, которые используют operator Base() член SomeOtherClass лет. (В этом случае более тщательно продуманное решение, включающее boost::disable_if<is_same<T, SomeOtherClass> >, может использоваться.) В любом случае, необходимо удалить этот код, после того как Вы определили все разрезание объектов-экземпляров.

конструкторам компилятора мира: Тестирование на объектное разрезание - определенно что-то, что было бы стоящим созданием (дополнительно) предупреждения для! Я не могу думать об одном экземпляре, где это было бы желаемое поведение, и это очень обычно замечается в новичке код C++.

[РЕДАКТИРУЮТ 27.03.2015:] , Как указано Matt McNab, Вы на самом деле не должны объявлять конструктора копии и оператор присваивания явно, поскольку я сделал выше, поскольку они будут все еще неявно объявлены компилятором. В стандарте C++ 2003 года это явно упоминается в сноске 106 под 12.8/2:

, поскольку шаблонный конструктор никогда не является конструктором копии, присутствие такого шаблона не подавляет неявное объявление конструктора копии. Шаблонные конструкторы участвуют в разрешении перегрузки с другими конструкторами, включая конструкторов копии, и шаблонный конструктор может использоваться для копирования объекта, если оно обеспечивает лучшее соответствие, чем другие конструкторы.

8
ответ дан 30 November 2019 в 12:20
поделиться

Я предложил бы добавить конструктора к Вашему базовому классу, который берет ссылку константы на производный класс явно (с предописанием). В моем простом тестовом приложении этого конструктора вызывают в режущем случае. Вы могли затем, по крайней мере, получить утверждение во время выполнения, и Вы могли, вероятно, получить утверждение времени компиляции с умным использованием шаблонов (например: инстанцируйте шаблона способом, который генерирует утверждение времени компиляции в том конструкторе). Могут также быть особенные методы компилятора получить предупреждения времени компиляции или ошибки, когда Вы вызываете явные функции; например, можно использовать "__ declspec (удержанный от использования)" для "конструктора части" в Visual Studio для получения времени компиляции, предупреждая, по крайней мере, в случае вызова функции.

Так в Вашем примере, код был бы похож на это (для Visual Studio):

class Base { ...
    __declspec(deprecated) Base( const Derived& oOther )
    {
        // Static assert here if possible...
    }
...

Это работает в моем тесте (время компиляции, предупреждая). Обратите внимание, что это не решает случай копии, но так же созданный оператор присваивания должен добиться цели там.

Hope это помогает. :)

4
ответ дан 30 November 2019 в 12:20
поделиться

Это обычно называют Объект, Режущий , и является достаточно известной проблемой, чтобы иметь ее собственную статью Wikipedia (хотя это - только краткое описание проблемы).

я полагаю, что использовал компилятор, который имел предупреждение, что Вы могли включить, чтобы обнаружить и предупредить об этом. Однако я не вспоминаю, какой, который был.

1
ответ дан 30 November 2019 в 12:20
поделиться

Едва ли решение Вашей непосредственной проблемы, но....

Большинство функций, которые берут объекты класса/структуры в качестве параметров, должно объявить, что параметры типа "константа X&"; или "X&"; если у них нет очень серьезного основания не к.

, Если Вы всегда делаете это, объектное разрезание никогда не будет проблемой (ссылки не становятся нарезанными!).

1
ответ дан 30 November 2019 в 12:20
поделиться

Лучший способ сражаться с этой проблемой состоит в том, чтобы обычно следовать рекомендации Scott Meyer (см. Эффективный C++ ) только наличия реальных классов в вершинах Вашего дерева наследования и гарантируя, что нелистовые классы абстрактны при наличии по крайней мере одной чистой виртуальной функции (деструктор, если ничто иное).

удивительно, как часто этот подход помогает разъяснить дизайн другими способами, также. Усилие по изоляции общего абстрактного интерфейса обычно является стоящей конструкторской разработкой в любом случае.

Редактирование

, Хотя я первоначально не ясно дал понять это, мой ответ прибывает из того, что не возможно предупредить точно об объекте, режущем во время компиляции, и поэтому это может привести к ложному чувству защищенности, если у Вас есть утверждение времени компиляции, или предупреждение компилятора включило. Если Вы должны узнать о разрезании объектов-экземпляров и должны исправить их затем, оно подразумевает, что у Вас есть требование и способность изменить унаследованный код. Если это верно, затем я полагаю, что необходимо серьезно рассмотреть рефакторинг иерархии классов как способ сделать код более устойчивым.

Мое обоснование - это.

Рассматривают некоторый код библиотеки, который определяет класс Concrete1 и использует его в inferface к этой функции.

void do_something( const Concrete1& c );

Передача типа быть ссылкой для эффективности и является, в целом, хорошей идеей. Если библиотека полагает, что Concrete1 тип значения, реализация может решенный для создания копии входного параметра.

void do_something( const Concrete1& c )
{
    // ...
    some_storage.push_back( c );
    // ...
}

, Если тип объекта переданной ссылки, действительно, Concrete1 и не некоторый другой производный тип затем, этот код прекрасен, никакое разрезание не выполняется. Общее предупреждение на этом push_back вызов функции мог бы произвести только ложные положительные стороны и скорее всего будет бесполезен.

Рассматривают некоторый клиентский код, который получает Concrete2 от Concrete1 и передает его в другую функцию.

void do_something_else( const Concrete1& c );

, поскольку параметр взят ссылкой, которую никакое разрезание не происходит здесь на параметре для проверки, таким образом, это не было бы корректно для предупреждения здесь о разрезании, поскольку может случиться так, что никакое разрезание не происходит. Передача в производном типе к функции, которая берет ссылку или указатель, является общим и полезным способом использовать в своих интересах полиморфные типы, настолько предупреждающие или запрещающие, это казалось бы контрпродуктивным.

Поэтому, где там ошибка? Хорошо 'ошибка' является передающей в ссылке на что-то, что получено из класса, который затем рассматривают, как будто это - тип значения вызванной функцией.

нет, в целом, никакого способа генерировать последовательно полезное время компиляции, предостерегая от объектного разрезания, и это - то, почему лучшая защита, если это возможно, состоит в том, чтобы устранить проблему дизайном.

1
ответ дан 30 November 2019 в 12:20
поделиться
class Derived: public Base{};

Вы говорите Полученный, Основа, и таким образом, она должна работать в любой функции, которая берет основу. Если это - настоящая проблема, возможно, наследование не то, что Вы действительно хотите использовать.

1
ответ дан 30 November 2019 в 12:20
поделиться

Я изменил Ваш код немного:

class Base{
  public:
    Base() {}
    explicit Base(const Base &) {}
};

class Derived: public Base {};

void Func(Base)
{

}

//void Func(Derived)
//{
//
//}

//main
int main() {
  Func(Derived());
}

явное ключевое слово удостоверится, что конструктор не будет использоваться в качестве неявного оператора преобразования - необходимо назвать его явно, когда Вы хотите использовать его.

0
ответ дан 30 November 2019 в 12:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: