Я вижу то же самое в отладчике, что и вы; Я не знаю наверняка, но я подозреваю, что материал становится инкрустированным. Деструктор для basic_string
очень мал; один тест (для оптимизации небольших строк), а затем вызов функции распределителя deallocate
(через allocate_traits
). std::allocator
s функция распределения также довольно мала, просто обертка вокруг operator delete
.
Вы можете проверить это, написав собственный распределитель. (Позже: см. Ниже)
Больше материала, которое я создал при расследовании этого вопроса; прочитайте, если вы заинтересованы.
[Примечание: есть ошибка в вашем коде - во второй строке Вы писали: mystr1.begin(),mystr.end())
- где mystr1
объявлен?]
Если предположить, что это опечатка, я попробовал некоторые немного другой код:
#include <string>
#include <new>
#include <iostream>
int news = 0;
int dels = 0;
void * operator new (size_t len) throw (std::bad_alloc)
{
void * mem = malloc(len);
if ((mem == 0) && (len != 0))
throw std::bad_alloc();
++news;
return mem;
}
void operator delete (void * ptr) throw()
{
++dels;
if (ptr != 0)
free(ptr);
}
int main(int argc, const char * argv[])
{
{
std::string mystr("testing very very very big string for string class");
std::string mystr2(mystr.begin(),mystr.end());
std::cout << "News = " << news << "; Dels = " << dels << std::endl;
}
std::cout << "News = " << news << "; Dels = " << dels << std::endl;
}
Если запустить этот код, он печатает (по крайней мере для меня):
News = 2; Dels = 0
News = 2; Dels = 2
, что и должно быть.
Если я брошу код в compiler explorer, то я вижу оба звонка на basic_string::~basic_string()
, точно так, как я ожидаю. (Ну, я вижу три из них, но один из них находится в блоке обработки исключений, который заканчивается вызовом _Unwind_resume
).
Позже - этот код:
#include <string>
#include <new>
#include <iostream>
int news = 0;
int dels = 0;
template <class T>
class MyAllocator
{
public:
typedef T value_type;
MyAllocator() noexcept {}
template <class U>
MyAllocator(MyAllocator<U>) noexcept {}
T* allocate(std::size_t n)
{
++news;
return static_cast<T*>(::operator new(n*sizeof(T)));
}
void deallocate(T* p, std::size_t)
{
++dels;
return ::operator delete(static_cast<void*>(p));
}
friend bool operator==(MyAllocator, MyAllocator) {return true;}
friend bool operator!=(MyAllocator, MyAllocator) {return false;}
};
int main(int argc, const char * argv[])
{
{
typedef std::basic_string<char, std::char_traits<char>, MyAllocator<char>> S;
S mystr("testing very very very big string for string class");
S mystr2(mystr.begin(),mystr.end());
std::cout << "Allocator News = " << news << "; Allocator Dels = " << dels << std::endl;
}
std::cout << "Allocator News = " << news << "; Allocator Dels = " << dels << std::endl;
}
печатает:
Allocator News = 2; Allocator Dels = 0
Allocator News = 2; Allocator Dels = 2
, который подтверждает, что аллокатор вызывался.
Вы включили оптимизацию? Почему вы считаете это идеальным, что деструктор называется? Поскольку единственным наблюдаемым эффектом деструктора является вызов для удаления, это допускается по правилу as-if. – user2079303
Я не включил оптимизацию, я знаю, что для basic_string он вызовет оператор new из ассемблерного кода, но в случае создания второй строки он использует распределитель и вызывает новый оператор через метод allocate. Я также вижу деструктор в классе basic_string, и, посмотрев код, я чувствую, что его написанный для вызова в момент уничтожения для случая, когда строка была создана через распределитель. –