LINUX.ORG.RU

Вопросик по C++ NULL

 ,


0

1

Я тут изучаю с++ ) Не могу понять как мне проверить что объект создан?

Process{
  public:
    Process(const char* cmd_){}
  ...
}


далее я объявляю
Process ffplay=NULL;

if(ffplay){} //ошибка
//conditional expression of type 'Process' is illegal

if(ffplay != NULL && !ffplay.isClosed()){} //ошибка
//binary '!=': no operator found which takes a left-hand operand of type 'Process' (or there is no acceptable conversion)



ffplay ведь изначально NULL(=0)

★★★★

чел это не Java, а плюсы.

Process globalOne;

int main() {
    static Process staticOne;
    Process localOne;
    Process onHeap = new Process();
}

если конструктор не кинул исключение, то значит создан.

но надо с memory model начинать изучать.

drsm ★★ ()

Я тут изучаю с++ ) Не могу понять как мне проверить что объект создан?

культурные люди давно уже пишут не архаичный NULL, а nullptr. это специальная константа типа указатель, со значением - «никуда не указываю», то что оно технически и равно нулю, это не ваше дело. никто не гарантирует что оно нулю равно. NULL или того хуже - 0 , вообще deprecated. и проверяют на nullptr указатели на инстансы, а не сами инстансы.

alysnix ()
Ответ на: комментарий от xaizek

Так есть объект всегда создается, даже если объявить NULL (да, смотрю в дебаге точно создается)? Тогда как он создается, если у меня нет default констурктора? Кстати когда объявляешь без NULL, то компилятор ругается именно на его отсутствие. А с NULL не ругается, но все равно создает. Каким образом?

gobot ★★★★ ()
Ответ на: комментарий от gobot

когда объявляешь без NULL, то компилятор ругается именно на его отсутствие. А с NULL не ругается, но все равно создает.

У тебя конструктор принимает 1 параметр типа char*, а конструктора по умолчанию (без параметров) нет, потому и ругается. Объект и указатель на объект — разные вещи. Объект не может быть NULL, а указатель — может. Когда ты присваиваешь объекту NULL, ты присваиваешь его по сути своему cmd_. Для понимания си и си++ первым делом надо понять указатели, ссылки и массивы, работа с которыми здесь сильно отличается от java и многих других языков. Остальное более-менее так же, если не считать множества идиотских нововведений в крестах.

aureliano15 ★★ ()

А в плюсах, (где все по честному) если ты написал

T var

то обьект будет создан в глобальной памяти или на стеке функции(в зависимости где ты это написал) и прибит или при выходе из программы, или при выходе из блока {…}, где ты его обьявил. если обьект так обьявлен, то в месте его использования он гарантированно создан, иначе будет какой-нить эксепшн, и потому успехе создлания проверять не надо. он гарантирован.

а чтобы создать его на куче в любой тебе нужный момент - надо писать

T* ptr = new T…

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

но тут можно(хоть это и параноидально) проверять на успех создания. тебе new не создаст обьект, если память кончилась. но тогда сама прога скорее всего упадет раньше.

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

alysnix ()

у тебя какая-то старая книжка по плюсам. NULL - это с++98, в с++11 уже nullptr. обнови литературку. а лучше возьми какую-нибудь брошюрку по си, там одной из первых глав будет про указатели. это надо знать. по си книжка будет не большой, всё что ты там прочитаешь пригодится в с++.

anonymous ()
Ответ на: комментарий от alysnix

тебе new не создаст обьект, если память кончилась. но тогда сама прога скорее всего упадет раньше.

Тогда выбросится исключение std::bad_alloc, и его можно будет перехватить и обработать. А вот если не обрабатывать, тогда обработчик по умолчанию прервёт прогу. NULL new возвратит только в режиме совместимости с совсем древним кодом, но для этого нужно явно задать соответствующие опции компиляции.

aureliano15 ★★ ()
Ответ на: комментарий от anonymous

NULL - это с++98, в с++11 уже nullptr.

Да все эти приблуды типа nullptr — лишние сущности. Вполне себе можно использовать NULL и даже 0, и ничего не изменится. Единственно, 0, когда речь идёт о пустом указателе, иногда не очень читабелен. А NULL в этом смысле вообще идеален и совместим с любыми версиями. Но если очень хочется быть новомодным, то можно и nullptr.

aureliano15 ★★ ()
Ответ на: комментарий от aureliano15

Тогда выбросится исключение std::bad_alloc, и его можно будет перехватить и обработать.

поправку принимаю.

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

alysnix ()
Ответ на: комментарий от alysnix

проверять на nullptr после new - это смысла не имеет, хотя так иногда делают.

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

aureliano15 ★★ ()
Ответ на: комментарий от gobot

Нет. std::unique_ptr юзай + объект получай через синглтон (время создания глоальных объекто неопределено).

А то потом начнешь - цпп дерьмо, там даже сборщика мусора нет.

pavlick ★★ ()
Последнее исправление: pavlick (всего исправлений: 1)
Ответ на: комментарий от anonymous

Садись, два.

по поведению это константа уникального типа вроде суперобобщенного указателя, обобщеннее чем void*, который вводится через нее саму. то есть полная вещь в себе, встроенная в компилятор. тип имеет только одно значение - nullptr. сам тип явно не вводится, хотя и считается фундаментальным, скорее всего чтобы список зарезервированных слов не расширять. получить это тип можно только через decltype(nullptr), или вкачать хидер, в котором ровно это и написано.

alysnix ()
Ответ на: комментарий от alysnix

nullptr. это специальная константа типа указатель

Не константа, а значение. Ты же говоришь, что true - это специальная константа или 5 - специальная константа. Если мы говорим про константу в c++, то это что-то что объявлено, как const.

rumgot ★★★★★ ()
Ответ на: комментарий от aureliano15

Вполне себе можно использовать NULL и даже 0, и ничего не изменится

Изменится безопасность. nullptr имеет специальный тип и по ошибке ты его не присвоишь или не сравнишь с переменной int, а NULL вполне. Дело не в моде, а в том, чтобы переложить на компилятор больше контроля типов.

rumgot ★★★★★ ()

Вообще в треде глупостей на квадратный метр аж перебор. Большинство вопросов отпали бы сами собой после средней арифметической книги по основам.

rumgot ★★★★★ ()
Последнее исправление: rumgot (всего исправлений: 1)
Ответ на: комментарий от rumgot

nullptr_t https://en.cppreference.com/w/cpp/types/nullptr_t

вы просто не поняли что там написано.

true и false - константы(ну назовите это константыми значениями) типа bool. все три сущности являются зарезервированными (keywords) словами языка. смотрите сюда - https://en.cppreference.com/w/cpp/keyword

тип bool - полновесный встроенный тип, и вы можете писать

bool var = true;

в том же списке есть слово nullptr, но там нет слова nullptr_t. и компилятор не знает что это. и без явного определения этого типа ручками через decltype(nullptr) не поймет о чем речь. то есть компилятор знает что nullptr типизирован, но это встроенный анонимный тип.

попробуйте рядом с

bool x = true

написать(не проинклудив ничего)

nullptr_t y = nullptr.

вас пошлют подальше и скажут что нет nullptr_t неопределен.

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

alysnix ()
Ответ на: комментарий от anonymous

POSIX гарантирует…

и это радует!… но надо было с самого начала вводить специальный тип и константу «никуда не указываю». а не какие-то целочисленные затычки и левые гарантии.

alysnix ()
Ответ на: комментарий от alysnix

вас пошлют подальше и скажут что нет nullptr_t неопределен.

но почему? https://godbolt.org/z/b7r1qb

никто же не мешает сделать using nullptr_t = decltype(nullptr) руками и будет свой nullptr_t. откуда это вообще взялось, что nullptr_t якобы недоступен. может компилятор кривой?

anonymous ()
Ответ на: комментарий от anonymous

никто же не мешает сделать using nullptr_t = decltype(nullptr) руками и будет свой nullptr_t.

а я о чем? такого типа в явном виде нет, он снабжается алиасом в общем случае юзером(в частном случае - системным хидером), через получение типа от константы nullptr.

это все равно что убрать из языка bool, и сделать пользовательский тип bool_t, что будет алиасить decltype(true).

а заодно убрать и int и алиасить decltype(666), и вообще все фундаментальные типы убрать, и алиасить какие то константы. появляется масса возможностей для интересной жизни

alysnix ()
Ответ на: комментарий от alysnix

true и false - константы(ну назовите это константыми значениями)

Значение слова константа - достаточно широкое, но в контексте обсуждения в данном случае C++ лучше использовать термин значение, чтобы не было разночтения, т.к. под константами обычно подразумевается нечто помеченное как const.

rumgot ★★★★★ ()
Ответ на: комментарий от alysnix

Ты не понял, что я тебе написал и сразу попытался искать ошибки в моих сообщениях.

Ты написал, что тип не явно вводится. Тип вводится, просто ключевого слово нет.

Можно даже так написать и получить имя:

// g++ 9.3.0

std::cout << typeid(nullptr).name() << std::endl;
// вывод:
// Dn
//
// далее в терминале расшифровываем:
// c++filt -t Dn
// результат (какая неожиданность):
// decltype(nullptr)
rumgot ★★★★★ ()
Последнее исправление: rumgot (всего исправлений: 2)
Ответ на: комментарий от anonymous

Еще раз, nullptr нужен для большей типобезопасности:

class A {
public:
  A(int i) : i_(i) {}
private:
  int i_;
};

int main() {
  A a = NULL; // Ok
  A a2 = nullptr; // Ошибка компиляции

  int j = 20;
  if (j == NULL) {} // Ok
  if (j == nullptr) {} // Ошибка компиляции 
}

Вот чтобы таких запретить такие случаи, где стоит Ok и нужен nullptr.

rumgot ★★★★★ ()
Последнее исправление: rumgot (всего исправлений: 5)
Ответ на: комментарий от rumgot

Вот чтобы таких запретить такие случаи, где стоит Ok и нужен nullptr.

или пользоваться предупреждениями компилятора. Ты то ими не пользуешься :)

error: implicit conversion of NULL constant to 'int' [-Werror,-Wnull-conversion]
  A a(NULL); // Ok
    ~ ^~~~
      0
error: comparison between NULL and non-pointer ('int' and NULL) [-Werror,-Wnull-arithmetic]
  if (j == NULL) {} // Ok
      ~ ^  ~~~~

А так, я за nullptr. Но показывать примеры, которые ловит компилятор и с NULL, это такое себе…

fsb4000 ★★★★ ()
Ответ на: комментарий от alysnix

Ее все равно придется как то хранить, что это меняет? Давай ещё ABI ядра поменяем так, чтобы open(2) не число возвращал при ошибке, а специальный тип и константу «ничего не вышло».

anonymous ()
Ответ на: комментарий от alysnix

но зачем тебе нужен nullptr_t, чтобы передать его в функцию параметром или что? а если он тебе действительно для чего-то понадобился, например ты пишешь шаблоны, то почему бы тебе не включить ?

auto y = nullptr;

какой тип будет у y? ну доступен же тип, почему не доступен? алиаса действительно нет, ну вот так сделали, алиаса нет, наверное посчитали, что не стоит объявлять. опять же, зачем он тебе вообще нужен?

anonymous ()
Ответ на: комментарий от fsb4000

Ты то ими не пользуешься :)

Какой ты офигенный психолог, ну прям Фрейд новоиспеченный. Типо-безопасность самого языка удобнее когда не нужно еще играться с ключами компиляции, которые к тому же не закреплены стандартом самого языка (кстати такой флаг есть например в MSVC?).

rumgot ★★★★★ ()
Последнее исправление: rumgot (всего исправлений: 3)
Ответ на: комментарий от anonymous

но зачем тебе нужен nullptr_t

Иногда нужен. https://en.cppreference.com/w/cpp/types/nullptr_t

If two or more overloads accept different pointer types, an overload for std::nullptr_t is necessary to accept a null pointer argument.
#include <cstddef>
#include <iostream>
 
void f(int*)
{
   std::cout << "Pointer to integer overload\n";
}
 
void f(double*)
{
   std::cout << "Pointer to double overload\n";
}
 
void f(std::nullptr_t)
{
   std::cout << "null pointer overload\n";
}
 
int main()
{
    int* pi {}; double* pd {};
 
    f(pi);
    f(pd);
    f(nullptr); // would be ambiguous without void f(nullptr_t)
    // f(0);    // ambiguous call: all three functions are candidates
    // f(NULL); // ambiguous if NULL is an integral null pointer constant 
                // (as is the case in most implementations)
}
rumgot ★★★★★ ()
Ответ на: комментарий от rumgot

Типо-безопасность самого языка удобнее когда не нужно еще играться с ключами компиляции, которые к тому же не закреплены стандартом самого языка.

Не любит «играться с ключами компиляции, которые к тому же не закреплены стандартом самого языка», бедолага, вестимо, собирает свой код с -O0. Хреново быть тобой.

anonymous ()