С недавним открытием, что код <code class="cpp">const int* Number = &static_cast<const int&>(1);</code> является допустимым, возникает вопрос: было ли это разрешено всегда? Ранее я полагал, что указатель может ссылаться только на lvalue или на данные в куче.
В приведенном вами коде есть несколько моментов, которые стоит обсудить. Для начала, рассмотрим ваше утверждение о том, что "указатель может ссылаться только на lvalue или на данные в куче". Это не совсем так. Указатели в C++ могут указывать на любые объекты, включая временные (temporary) значения, которые являются rvalue. Ваша строка кода: ```cpp const int* Number = &static_cast<const int&>(1); ``` является допустимой, но есть некоторые нюансы: 1. В C++ числовая литерал `1` является rvalue. Однако, когда вы используете `static_cast<const int&>(1)`, вы создаете временный объект, который может быть "привязан" к lvalue-ссылке, потому что временные значения могут быть связаны с константной lvalue-ссылкой. 2. Временные объекты в C++ существуют в области видимости, пока они не перестанут использоваться, но в вашем случае — вы имеете дело с указателем на временный объект, который будет уничтожен сразу после завершения выражения. Это означает, что указатель `Number` будет указывать на память, которая больше не действительна, и доступ к этой памяти приведет к неопределенному поведению. Таким образом, хотя ваш код компилируется и вполне допустим, он не является хорошей практикой, так как указатель `Number` не будет указывать на корректный адрес после завершения соответствующего выражения. Если же вы хотите сохранить единицу как `const int`, вам стоит использовать статическую переменную или динамическое выделение памяти: ```cpp const int temp = 1; const int* Number = &temp; ``` Или: ```cpp const int* Number = new int(1); // Не забывайте освобождать память позже ``` Теперь `Number` будет указывать на валидный объект, чья жизнь будет длиться дольше, чем жизнь временного объекта.
В наше время можно просто проверить: <a href="https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQBnPFgB3oH1kxVBw4A6ZDx6kqqBgQDKyJvRABGACwy5BAKodMABQAeIAOQAGM6QBW60rSYNQyAKQAmAEIfPpA/WQCPDlKRnQAYVRaAFcWBhAAVgBmUjCAGTwGTAA5WIAjTGJE0h4RQmCGSJi4xJTSriC5DKzclgKihL9MAMaGBQImYgIq2Pjkrp6K/sGCZpz8wuKOAaGRmvHlmbnW9sSASj9UaOJkdjNXCwBBNAZlgGpMggAqO53Cu9ckgBEP9wA2TZBZCCJjLT7hG73R4eP6fbAQNR7T7eK4Xa5yKHyF4cACO0UGmAgew%2BAHYUZc7pS7pCCA8sa8FsQPt9fgCBkCQWCkhCMbTof84QikUlyVS7sRMARjgwGW1Csi0a4SV8zAdaOYEtZ4mY1NZUJxuHxMIJhKIJFJSARzFY9gcANYgf5idxqNQATgAHBZ3a6NC61B6HOYNFrrXrzNYOCALJawwc4LAkGheHRCuRKMmeKmisBNO4ZHQCIUoxA8mHSHlMoMAJ7mXUVqvEasAeTyNkwgTr1mTbHkzYYtFrlmsWDy0WA4RUtCjOpHmBYTmAqmHpHwEsCeAAbpgZ1ZUsYO9Ei13yPJuuXaHg8sQa5EsOWCMRuCft8Q8iJMF954vL844zJHGADgADU8EwAB3ZseEYE9ZHkJQVHYTRtHkfQjFMFc7DUBxFxQHwfAcK8o0gA5UB4XoZz1V8nywYiiQmDtelCBgIiiUZ7HSTJ5jlIpsPqco5DWeI%2BLKXptkZex/EYqYVmGNiamwqSNzkaYhnEnjJNkoTNK2Li3l4g4OCOE4kLVDVQxXfUzDuYwPT%2BABaP4NDuYBkGQO5NGdO4IFwQgSF%2BJJEWsK1h1tUgHXcJIxBJD0vXdL1YoSGK3RSdUzBDUhtT3KzI2jWNQtIBNEBQVAU3oMgKAgTNsxQRxnH4R9ogYO0C1oItiBLMsV0rZgmxPHqa1bdtO1nUge0YAh%2B0HctR3HSdaGnE8sAXZxlz3NdpO3XdrEwA9kCPM560ec8V0va9bwwM490fZ9Rtfd8DC/Fal0yUACqoQCQLAyDoO1es4MUZRVGQgG0JMcs7HzOqXHwrxCLyOjSPIipKNIVBqLwWj4EM7ppJCCAwm07DOJaCSRIaCoiZKUSKnU3ZFNx5S%2Bi0%2BThIYpnVNmPSyb8FnqjZzY1O5jTEUOY5TnUMyzE1TLyysmy7Mc5zkGh7zGua4kfPwIgmQ8QK9mCuN7UdTo0oyrLwzMXKYxCm1CpgYqjgIHgj3TKrSqzcrslYM5bIcpyXLcjyNDEetMG1khMfsAGEOBrRQYMcHMMdUhwJvHguylmWLbR8xmyPF3aVQKgFf95XVYgdW7U1yIyvePX3AN/KbWN9xTeDCzsojPw8tt1UpfcTvLcN0KDlfLgQg0IA%3D%3D" rel="nofollow">godbolt.org</a> <br/> <br/> И clang и g++ и при локальном и при глобальном объявлении кладут 1 на стек. <br/> Правда, clang чуть поумнее и выдает warning: <br/> <blockquote>warning: temporary whose address is used as value of local variable 'Number' will be destroyed at the end of the full-expression [-Wdangling]</blockquote> <br/> <br/> Нельзя надеяться, что по этому адресу останется лежать 1. В более сложных случаях этот адрес может быть переиспользован под что-то еще. Обращение по такому указателю - UB.
Не пиши так, пожалуйста. <br/> Перед нами продление жизни временного объекта. <br/> Когда ссылка исчезнет — а она исчезнет после точки с запятой — указатель будет смотреть в никуда, и только от Ктулху зависит, когда переменную перезапишут. <br/> Правильно так: <br/> <pre><code class="cpp">const int& ref = 1; const int* Number = &ref;</code></pre> <br/> Данные могут лежать где угодно — теоретически на стеке, но оптимизатор может перекинуть их и в сегмент данных. <br/> <br/> В общем, правило. <b>Продлённый объект живёт, пока живёт та ссылка, что его продлила.</b> Ссылки и указатели, что сделаны уже из этой ссылки, не в счёт: Си++ всё-таки не «мусорный» язык. <b>Временный объект живёт до точки с запятой</b> , за исключением нескольких случаев: явная команда придержать объект (о которой у нас и речь), создание/копирование массива (для простоты компиляции и чтобы не раздувать стек), с Си++23 в команде «цикл по объекту» ради безопасности и предсказуемости.
Данные будут храниться в сегменте .rodata или .text
Если это определение внутри функции/метода - то Number будет лежать на стеке. <br/> Если вне функции/метода - в области глобальных данных. <br/> А вот данные на которые указывает Number могут лежать где угодно. <br/> Да, указатель может указывать и на данные на стеке или в глобальной области. В общем на любой выделенный блок памяти он может указывать. А в вашем примере даже и не на выделенный, только обращаться по такому указателю нельзя.