std :: allocator_traits :: construct с указателем const - PullRequest
5 голосов
/ 08 июля 2019

Следующий код прекрасно компилируется:

#include <iostream>
#include <memory>
int main()
{
const int * a = new int(5);

std::cout << *a << std::endl; // Prints 5

// *a = 5; // Compiler error.
using at = std::allocator_traits<typename std::allocator<int>>;
auto alloc = std::allocator<int>();
at::construct(alloc, a);

std::cout << *a << std::endl; // Prints 0
}

Под капотом libstdc ++ делает

::new((void*)a) int;

, но a равно const!

Не определено ли этоповедение?Или размещение новых не считается изменением?Я изменил значение *a, которое является постоянным.Насколько я понимаю, это недопустимо:

Изменение константного объекта через неконстантный путь доступа и обращение к энергозависимому объекту через энергонезависимое glvalue приводит к неопределенному поведению.

https://en.cppreference.com/w/cpp/language/const_cast

Ответы [ 2 ]

4 голосов
/ 09 июля 2019

TL; DR : штраф до C ++ 2a, после этого std::allocator_traits<std::allocator<int>>::construct() будет более требовательным к переданному указателю.


Ну, std::allocator_traits::construct() использует static_cast<void*>, так как он был введен , если только распределитель не предоставит его.

И хотя std::allocator::construct() устарело в C ++ 17 и будет удалено в C ++ 2a, оно всегда использовало приведение в стиле c.

Таким образом, это синтаксически допустимо до C ++ 2a.


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

Поскольку псевдодтор для int тривиален, даже не имеет значения, что он не вызывается до создания нового поверх него.

0 голосов
/ 08 июля 2019

const int* a указывает, что значение, содержащееся в слоте памяти, указанном a, является постоянным, но не сам указатель.

#include <memory>

int main()
{
    const int * a = new int;

    a = nullptr; // Compile fine
    *a = 1; // Won't compile

    return 0;
}

Вы ожидали, что ваш код будет вести себя как:

#include <memory>

int main()
{
    int* const a = new int;

    a = nullptr; // Won't compile
    *a = 1; // Compile fine

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...