2015-11-25 4 views
2

Я создаю класс, у которого есть конструктор, инициализированный из const char*, который должен безопасно построить объект, используя данные, предоставленные в буфере, который должен содержать строку. Мои заботы состоят в том, что пользователь может использовать этот конструктор с неправильными данными, например. NULL указатель или указатель на выделенную память или что-то в этом роде. Дело в том, что в этом случае я хочу закончить создание объекта (который будет находиться в неопределенном, но правильном состоянии), не вызывая segfault, если, например, пользователь отправил мне указатель на данные, которые я не должен читать. Я думал послать все проверки ввода в std::string конструктора, так что конструктор будет выглядеть следующим образом:C++ - создание безопасного const char * contructor

Foo(const char *s) : Foo(std::string(s)) {} 

Но мой учитель назвал это «ложная идея». Итак, каков надлежащий способ справиться с этой ситуацией?

Еще одна вещь, я не могу использовать исключения в этом случае (это часть моего домашнего задания в курсе, который еще не научил его).

+1

Вам это не нужно - компилятор достаточно умен, чтобы понять, как использовать конструктор 'foo (std :: string)'. –

+0

На самом деле - мне это нужно. Мне нужно, чтобы конструктор 'foo (std :: string)' был 'explicit', чтобы предотвратить что-то вроде' foo x = "bar" '. – qiubit

+2

«неопределенное, но правильное состояние» кажется противоречием в терминах. На самом деле, вместо создания неопределенного объекта вы должны * почти наверняка * генерировать исключение в конструкторе, чтобы предотвратить создание неисправного объекта. Конечно, это зависит от практического варианта, но это часто правильное решение, которое я бы назвал абсолютным законом. –

ответ

7

Проблема в том, что есть некоторые вещи, которые вы абсолютно не можете проверить. Самая большая группа - указатель на недопустимую память. Например:

char* blarg = new char[50]; 
delete blarg; 
Foo(blarg); 

Here еще один разговор о том, что вы просите. Некоторые хорошие ответы есть, но они в основном говорят то же самое. При работе с входом указателя нет никакого способа, чтобы быть 100% уверены, что пользователь не делать что-то глупое как вызов удаления на указателе перед передачей его.

0

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

+0

На самом деле это не так, поскольку ОП четко заявил, что не может использовать исключения – BlackDwarf

+1

см. Его обновление «Еще одна вещь, я не могу использовать исключения в этом случае». – user1810087

+0

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

2

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

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

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

Я думал послать все проверки ввода в StD :: строка конструктор

Но мой учитель назвал это «ложная идея».

Ваш учитель верен. Это не поможет, потому что std::string также требует и предполагает, что вход действителен. Построение его с недопустимым указателем приводит к неопределенному поведению.

Итак, каков надлежащий способ справиться с этой ситуацией?

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

0

Если вы хотите проверить, что ваш класс принимает в качестве аргументов только std::string и const char[] вы можете написать что-то вроде этого:

class Foo { 
public: 

    template<typename U> 
    Foo(U &&val, typename std::enable_if<std::is_same<typename std::remove_reference<U>::type, std::string>::value || 
     std::is_array<typename std::remove_reference<decltype(val)>::type>::value, void>::type* = nullptr): field_(val) {} 
private: 
    std::string field_; 
}; 

Тогда:

Foo foo("aa");//accept 
std::string str("bb"); 
Foo foo2(str);//accept 
Foo fnull(NULL);//compile time error 

, конечно, это решение не работать, если вы хотите передать только указатель на char.

Смежные вопросы