AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 78950164
Accepted
Mikhail T.
Mikhail T.
Asked: 2024-09-05 02:51:03 +0800 CST2024-09-05 02:51:03 +0800 CST 2024-09-05 02:51:03 +0800 CST

Qual é a diferença entre passar NULL e nullptr para um parâmetro de modelo?

  • 772

Estou lidando com uma API razoavelmente uniforme fornecida por um fornecedor e gostaria de verificar -- e lidar -- com quaisquer falhas de forma unificada também. Para esse fim, escrevi o seguinte wrapper:

template <typename Func, typename... Args>
auto awrap(Func &func, Args&&... args)
{
    auto code = func(args...);

    if (code >= 0)
        return code;

    ... handle the error ...
};
...
awrap(handlepath, handle, path, NULL, 0, coll, NULL);

O comando acima compila bem com clang, mas o g++13 e o Microsoft VC++ reclamam dos dois argumentos NULL:

... error: invalid conversion from 'int' to 'const char*' [-fpermissive]
   87 |                 auto code = func(args...

Substituir os dois NULLs por nullptrresolve o problema, mas por que isso importa?

Provavelmente, o NULLé transformado em 0x0ou mesmo 0em algum lugar pelo pré-processador, mas a chamada original nunca levantou uma "sobrancelha". Usar NULL era perfeitamente adequado em:

handlepath(handle, path, NULL, 0, coll, NULL);

Por que isso é um problema (para alguns compiladores) quando usado em um wrapper?


ATUALIZAÇÃO : /usr/include/sys/_null.hno meu sistema FreeBSD tem o seguinte código:

#ifndef NULL

#if !defined(__cplusplus)
#define NULL    ((void *)0)
#else
#if __cplusplus >= 201103L
#define NULL    nullptr
#elif defined(__GNUG__) && defined(__GNUC__) && __GNUC__ >= 4
#define NULL    __null
#else
#if defined(__LP64__)
#define NULL    (0L)
#else
#define NULL    0
#endif  /* __LP64__ */
#endif  /* __GNUG__ */
#endif  /* !__cplusplus */

#endif

Então:

  1. para C, NULLé (void *)0;

  2. para clang++ NULLe nullptrsão a mesma coisa, enquanto para GNU pode não ser...

c++
  • 2 2 respostas
  • 761 Views

2 respostas

  • Voted
  1. Best Answer
    Remy Lebeau
    2024-09-05T02:55:48+08:002024-09-05T02:55:48+08:00

    Em muitas implementações, NULLé apenas um #definepara um literal inteiro 0 , por exemplo:

    #define NULL 0
    

    Você pode atribuir diretamente um literal 0 a qualquer ponteiro, e é por isso que passar NULLdiretamente para a função de destino funciona bem.

    Como você está passando NULLum parâmetro de modelo, esse parâmetro está sendo deduzido como tipo int, como diz a mensagem de erro.

    Nesta chamada:

    awrap(handlepath, handle, path, NULL, 0, coll, NULL);
    

    awrap()resolverá algo como isto:

    auto awrap(decltype(handlepath) &func, decltype(handle) arg1, decltype(path) arg2,
        int arg3, int arg4, decltype(coll) arg5, int arg6)
     // ^^^^^^^^                                 ^^^^^^^^
    {
        auto code = func(arg1, arg2, arg3, arg4, arg5, arg6);
        //                    error: ^^^^       error: ^^^^
        ...
    };
    

    Para atribuir uma intvariável a um ponteiro, você precisa de uma conversão de tipo explícita, que você não está usando.

    Enquanto nullptris do tipo nullptr_t, que também pode ser atribuído diretamente a qualquer ponteiro. Há apenas 1 valor possível de nullptr_t. Então, ao passar nullptrpara um parâmetro de template, esse parâmetro será deduzido como tipo nullptr_t. E o compilador sabe como atribuir a nullptr_ta um ponteiro.

    Nesta chamada:

    awrap(handlepath, handle, path, nullptr, 0, coll, nullptr);
    

    awrap()resolverá algo como isto:

    auto awrap(decltype(handlepath) &func, decltype(handle) arg1, decltype(path) arg2,
        nullptr_t arg3, int arg4, decltype(coll) arg5, nullptr_t arg6)
     // ^^^^^^^^^^^^^^                                 ^^^^^^^^^^^^^^
    {
        auto code = func(arg1, arg2, arg3, arg4, arg5, arg6);
        //                       OK: ^^^^          OK: ^^^^
        ...
    };
    

    Então, ao chamar seu modelo, você deve usar nullptr.

    Mas, se você quiser usá-lo NULL, você deve fazer a conversão de tipo como (char*)NULL(ou equivalente), ou qualquer outro tipo de ponteiro que o parâmetro esteja esperando, por exemplo:

    awrap(handlepath, handle, path, (char*)NULL, 0, coll, (char*)NULL);
    
    • 17
  2. user17732522
    2024-09-05T03:01:28+08:002024-09-05T03:01:28+08:00

    NULLé uma macro que pode ser definida como nullptrou como um literal inteiro de valor zero (por exemplo, 0ou 0L). Qual deles é definido pela implementação, mas como apenas a última opção é válida em C e pré-C++11, as chances de ver a última são boas.

    nullptré um objeto de nullptr_t. Qualquer expressão desse tipo é sempre uma constante de ponteiro nulo , o que significa que pode ser convertida implicitamente em um valor de ponteiro nulo de qualquer tipo de ponteiro.

    Uma expressão inteira de valor zero, no entanto, nem sempre é uma constante de ponteiro nulo. Especificamente, apenas literais inteiros de valor nulo são constantes de ponteiro nulo que podem ser convertidas em tipos de ponteiro.

    Então, se você passar 0diretamente para uma função esperando um char*que funcione bem, o literal 0será uma constante de ponteiro nulo e poderá ser convertido para o tipo de ponteiro implicitamente, resultando em um valor de ponteiro nulo.

    Mas você está passando o literal para awrapcomo um tipo inteiro (por dedução). Quando você usa o argumento em , func(args...)ele ainda é uma expressão inteira com valor zero, mas não é um literal inteiro . Portanto, o argumento não é uma constante de ponteiro nulo e não pode ser convertido implicitamente para char*.

    Então, você não pode passar 0um parâmetro de ponteiro pelo wrapper porque você deve nomear o literal exatamente onde a conversão deve ser aplicada. E se você pode usar NULLé definido pela implementação. Funciona se NULLacontecer de ser definido como nullptr, mas não se for um literal inteiro de valor zero.

    Esse é um bom exemplo do porquê only nullptrdeve ser usado. O comportamento de conversão implícito de literais inteiros de valor zero existe apenas por razões históricas herdadas de C. Se a linguagem fosse projetada hoje, duvido que alguém adicionaria um caso especial tão estranho às conversões. Normalmente, as conversões possíveis são determinadas pelo tipo e categoria de valor das expressões. Esse é o único caso especial em que o valor e a construção gramatical afetam o comportamento de conversão.

    • 2

relate perguntas

  • Por que os compiladores perdem a vetorização aqui?

  • Erro de compilação usando CMake com biblioteca [fechada]

  • Erro lançado toda vez que tento executar o premake

  • Como criar um tipo de octeto semelhante a std::byte em C++?

  • Somente operações bit a bit para std::byte em C++ 17?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle?

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Quando devo usar um std::inplace_vector em vez de um std::vector?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Martin Hope
    Aleksandr Dubinsky Por que a correspondência de padrões com o switch no InetAddress falha com 'não cobre todos os valores de entrada possíveis'? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer Quando devo usar um std::inplace_vector em vez de um std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB Por que o GCC gera código que executa condicionalmente uma implementação SIMD? 2024-02-17 06:17:14 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve