занятный тип string
1. Не нашел подходящих функций преобразования целых чисел в тип string. Можно выйти из положения вот так:
str = ltoa(98, a, 10);
но ведь должен быть более красивый метод? Неужели нет стандартных функций (что-то типа IntToStr в Билдере?).
2. Почему-то при присвоении переменной типа string достаточно длинной строки сишного типа в string'е пишется всякая ахинея. Например, после выполнения этого кода в s1 будет ерунда:
string s1;
int n = 0;
for (n = 0; n < 100; n++) {
a[n] = '1';
}
a[99] = 0;
s1 = a;
я, видимо, чего-то не понимаю, но при первых же попытках после перехода с Си на Си++ (MS Visual C++ 7) использовать класс string столкнулся с двумя совершенно неожиданными проблемами:
1. Не нашел подходящих функций преобразования целых чисел в тип string. Можно выйти из положения вот так:
str = ltoa(98, a, 10);
но ведь должен быть более красивый метод? Неужели нет стандартных функций (что-то типа IntToStr в Билдере?).
2. Почему-то при присвоении переменной типа string достаточно длинной строки сишного типа в string'е пишется всякая ахинея. Например, после выполнения этого кода в s1 будет ерунда:
string s1;
int n = 0;
for (n = 0; n < 100; n++) {
a[n] = '1';
}
a[99] = 0;
s1 = a;
Да, есть такое дело. По-моему в операторе = нет изменения размера string. Так что нужно сначала вызывать какой-нибудь preallocate.
Более красивых методов нет, есть только по-моему get buffer, release buffer, с помощью которых можно получать строки не меньшей длины, чем требуется.
Извини, но точные названия методов смотри в MSDN
2. Почему-то при присвоении переменной типа string достаточно длинной строки сишного типа в string'е пишется всякая ахинея. Например, после выполнения этого кода в s1 будет ерунда:
string s1;
int n = 0;
for (n = 0; n < 100; n++) {
a[n] = '1';
}
a[99] = 0;
s1 = a;
Всё логично. S1 это указатель на пустую строку а указатель на первый элемент масива типа чар. Кто же сказал укозателю типа стринг что нада ссылаться на весь масив а не на первый его элемент?
1. Не нашел подходящих функций преобразования целых чисел в тип string. Можно выйти из положения вот так:
str = ltoa(98, a, 10);
но ведь должен быть более красивый метод? Неужели нет стандартных функций (что-то типа IntToStr в Билдере?).
std::string - это класс из STL.
В стандарте С++ не сказано, что класс std::string должен содержать методы приведения из int. Это сделано в силу ряда причин.
Пожалуйста, красивые методы преобразований:
#include <sstream>
template <typename T>
std::string toString(T val)
{
std::ostringstream oss;
oss<< val;
return oss.str();
}
template<typename T>
T fromString(const std::string& s)
{
std::istringstream iss(s);
T res;
iss >> res;
return res;
}
2. Почему-то при присвоении переменной типа string достаточно длинной строки сишного типа в string'е пишется всякая ахинея. Например, после выполнения этого кода в s1 будет ерунда:
string s1;
int n = 0;
for (n = 0; n < 100; n++) {
a[n] = '1';
}
a[99] = 0;
s1 = a;
Да? А как ты проверял? :)
Скажу по секрету: все отлично работает, s1 отлично принял твой массив.
проверь добавив строчку
std::cout << s1;
Да, есть такое дело. По-моему в операторе = нет изменения размера string. Так что нужно сначала вызывать какой-нибудь preallocate.
Более красивых методов нет, есть только по-моему get buffer, release buffer, с помощью которых можно получать строки не меньшей длины, чем требуется.
Извини, но точные названия методов смотри в MSDN
Не надо ничего вызывать.
Как я уже и говорил, налицо отрицательное влияние С на С++.
Отвлекитесь от буферов, вы работаете с классом (инкапсуляция).
Всё логично. S1 это указатель на пустую строку а указатель на первый элемент масива типа чар. Кто же сказал укозателю типа стринг что нада ссылаться на весь масив а не на первый его элемент?
s1 - это не указатель, а экземпляр класса.
a[] - это тоже не указатель, а массив.
Про кто что кому сказал, вообще, бред какой-то.
a[] - это тоже не указатель, а массив.
Про кто что кому сказал, вообще, бред какой-то. [/QUOTE]
Про s1-полностью согласен, это хитрый указатель. Естественно это экземпляр класса.
a[] - массив. То же верно. А а? если это не указатель то что это? И что интересно произайдёт если:
char b;
b=a+10;
cout<<b<<endl;
Про s1-полностью согласен, это хитрый указатель. Естественно это экземпляр класса.
Это совсем не smart pointer.
Smart pointer подразумевает, что объект выглядит, как указатель (т.е. должен обладать интерфейсом указателя), а на самом деле является чем-то больше, т.е. обладает некоторой функциональностью. Smart pointer строится на операциях * и -> (operator *, operator ->).
std::string совсем не выглядит указателем.
a[] - массив. То же верно. А а? если это не указатель то что это? И что интересно произайдёт если:
char b;
b=a+10;
cout<<b<<endl;
a - это массив (кв.скобки я указал лишь для наглядности, имя переменной - a), а не указатель!
Хочешь убедиться?
Проверь: sizeof(a) == sizeof(char*)
Твой пример не скомпилируется, т.к. ты, видимо, допустил ошибку в определении b.
В исправленном примере
char* b;
b=a+10;
std::cout << b << std::endl;
произойдет следующее переменная a типа char[20] неявно приведется к указателю char*, далее произведется сложение и присвоение результата переменной b.
Это совсем не smart pointer.
Smart pointer подразумевает, что объект выглядит, как указатель (т.е. должен обладать интерфейсом указателя), а на самом деле является чем-то больше, т.е. обладает некоторой функциональностью. Smart pointer строится на операциях * и -> (operator *, operator ->).
std::string совсем не выглядит указателем.
А запорожец не выглядит машиной. Но смысл от этого стринга не меняестя. Сокрытие реализации...
a - это массив (кв.скобки я указал лишь для наглядности, имя переменной - a), а не указатель!
Хочешь убедиться?
Проверь: sizeof(a) == sizeof(char*)
Твой пример не скомпилируется, т.к. ты, видимо, допустил ошибку в определении b.
В исправленном примере
char* b;
b=a+10;
std::cout << b << std::endl;
произойдет следующее переменная a типа char[20] неявно приведется к указателю char*, далее произведется сложение и присвоение результата переменной b.
Да ошибка есть только не там, а: b = *(a+10) И если он приводится неявно к указателю на первый элемент массива, с какой стати стринг должен брать весь массив?
P.S. Приятно с вами Green спорить, много нового узнаю...
А запорожец не выглядит машиной. Но смысл от этого стринга не меняестя. Сокрытие реализации...
По твоему получается, что любой класс можно назвать "умным указателем" :)
"Умный указатель" потому и называется указателем, что им можно пользоваться как обычным указателем.
Вот несколько ссылок объясняющие, что такое smart pointer:
http://ootips.org/yonat/4dev/smart-pointers.html
http://www.boost.org/libs/smart_ptr/smart_ptr.htm
http://www.informit.com/articles/article.asp?p=25264
http://c2.com/cgi/wiki?SmartPointer
Андрей Александреску (думаю, это имя о что-то тебе говорит) говорит конкретно следущее:
A smart pointer is a C++ class that mimics a regular pointer in syntax and some semantics, but it does more.
Да ошибка есть только не там, а: b = *(a+10) И если он приводится неявно к указателю на первый элемент массива, с какой стати стринг должен брать весь массив?
Ну стандарт не полные идиоты писали...
Если оператору присваивания передается char*, то логично предположить, что передается строка символов, заканчивающаяся нулем. Поэтому в реализации класса string это и заложено.
std::string является специализацией класса std::basic_string:
в этом классе такой оператор присваивания выглядит следующем образом:
{ // assign [_Ptr, <null>)
return (assign(_Ptr));
}
_Myt& assign(const _Elem *_Ptr)
{ // assign [_Ptr, <null>)
return (assign(_Ptr, _Traits::length(_Ptr)));
}
где _Elem - это параметр шаблона принимающий для std::string значение char, а _Traits::length для std::char_traits<char> это
{ // find length of null-terminated string
return (::strlen(_First));
}
Надеюсь, я доказал, что в реализацию std::string зашито восприятие char*, как символьной строки.
По твоему получается, что любой класс можно назвать "умным указателем" :)
"Умный указатель" потому и называется указателем, что им можно пользоваться как обычным указателем.
Вот несколько ссылок объясняющие, что такое smart
Так чем запорожец от машины отличается? Я ж не спорю...
Ну стандарт не полные идиоты писали...
Если оператору присваивания передается char*, то логично предположить, что передается строка символов, заканчивающаяся нулем. Поэтому в реализации класса string это и заложено.
И кто сказал про идиотов? Я это даже не подрозумевал... Если так выглядит прошу прощения... А char* это не строка, а указатель на числовой тип(ну не помню точно размерность 8 бит кажется или 16). И предполажение того что предоваться будет строка, не совсем верно. Я что уже не могу передать последовательность чисел не связаных со строкой?
Так чем запорожец от машины отличается?
Не знаю, я плохо в автомобилях разбираюсь... :)
У меня всегда Tayota были...
А char* это не строка, а указатель на числовой тип(ну не помню точно размерность 8 бит кажется или 16). И предполажение того что предоваться будет строка, не совсем верно.
В данном случае (std::string) лишь оно и верно.
Я что уже не могу передать последовательность чисел не связаных со строкой?
Можешь, но только не в классе std::string.
Можешь создать свой класс, в том числе на базе basic_string, только придется создать новый класс traits, либо переопределить оператор = в basic_string. Вот пример, как сделать, чтоб принимался только первый символ:
#include <string>
// traits для примера сделаем на базе стандартного,
// переопределим лишь length()
struct alibabaich_char_traits :public std::char_traits<char>
{
static size_t __cdecl length(const _Elem *_First)
{ // find length of null-terminated string
return 1;
}
};
typedef std::basic_string<char, alibabaich_char_traits, std::allocator<char> > alibabaich_string;
main()
{
char a[] = "test string";
alibabaich_string str;
std::cout << str.c_str() << std::endl;
}
У меня всегда Tayota были...
И после этого плохо разбираешься?:)
И после этого плохо разбираешься?:)
Реклама toyota не входит в суть этого топика... :D
Я ж к ним под капот один раз заглядывал,- при покупке... :D
Реклама toyota не входит в суть этого топика... :D
Я ж к ним под капот один раз заглядывал,- при покупке... :D
Если а массив, то почему результат:
void foo(char a[19]){
std::cout<<sizeof(a)<<std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
char a[]="dlkghsdfjkllsdfjbv";
std::cout << sizeof(a) << std::endl;
foo(a);
Sleep(1000);
return 0;
}
19 и 4?
Если а массив, то почему результат:
void foo(char a[19]){
std::cout<<sizeof(a)<<std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
char a[]="dlkghsdfjkllsdfjbv";
std::cout << sizeof(a) << std::endl;
foo(a);
Sleep(1000);
return 0;
}
19 и 4?
Я думаю, это из за "дурной наследственности".
Опять же отрицательное влияние С на С++.
Если написать так:
{
std::cout << sizeof(a) << std::endl;
}
void foo(char a[19])
{
std::cout << sizeof(a) << std::endl;
}
то компилятор ругнется на то, что foo(char*) уже определен. Это говорит о том, что компилятор воспринимает char* и char[] в параметрах функции, как одно и тоже, т.е. неявно приводит char[] к char*. Сделано это, видимо, для совместимости с компиляторами С.
Теперь постараюсь передать массив без приведения.
Ссылки были введены в С++, и в С они отсутствуют.
Попробуем передать массив по ссылке, чтоб избежать неявного преобразования. Т.к. синтаксис не допускает указыавать ссылку при массиве, буду использовать шаблон:
#include <string>
template<typename T>
void foo(T&)
{
std::cout << sizeof T << std::endl;
}
int main()
{
char a[]="dlkghsdfjkllsdfjbv";
foo(a);
return 0;
}
Пишет 19. ЧТД :)
Я думаю, это из за "дурной наследственности".
Опять же отрицательное влияние С на С++.
Ну, не надо про "дурное", сам же говорил что стандарт не идиоты придумали. Что дали с тем и работаем...
Если написать так:
{
std::cout << sizeof(a) << std::endl;
}
void foo(char a[19])
{
std::cout << sizeof(a) << std::endl;
}
то компилятор ругнется на то, что foo(char*) уже определен. Это говорит о том, что компилятор воспринимает char* и char[] в параметрах функции, как одно и тоже, т.е. неявно приводит char[] к char*. Сделано это, видимо, для совместимости с компиляторами С.
...Без коментариев.
Теперь постараюсь передать массив без приведения.
Ссылки были введены в С++, и в С они отсутствуют.
Попробуем передать массив по ссылке, чтоб избежать неявного преобразования. Т.к. синтаксис не допускает указыавать ссылку при массиве, буду использовать шаблон:
#include <string>
template<typename T>
void foo(T&)
{
std::cout << sizeof T << std::endl;
}
int main()
{
char a[]="dlkghsdfjkllsdfjbv";
foo(a);
return 0;
}
Пишет 19. ЧТД :)
Может так оно и есть... А может и нет. Буду копать в литературе, найду напишу, пока буду придерживаться твоей точки зрения....
Может так оно и есть... А может и нет. Буду копать в литературе, найду напишу, пока буду придерживаться твоей точки зрения....
Стандарт C++ подойдет?
http://www.csci.csusb.edu/dick/c++std/cd2/decl.html#dcl.array
Конкретно место:
1 In a declaration T D where D has the form
D1 [constant-expressionopt]
and the type of the identifier in the declaration T D1 is "derived-declarator-type-list T," then the type of the identifier of D is an array type.
Вот ещё наглядный пример:
typedef int A[5], AA[2][3];
typedef const A CA; // type is ``array of 5 const int''
typedef const AA CAA; // type is ``array of 2 array of 3 const int''
заметь, не о каких указателях не говорится.
А вот про стандартное преобразование
http://www.csci.csusb.edu/dick/c++std/cd2/conv.html#conv.array
Конкретное место:
А здесь про преобразование в списке аргументов функции:
http://www.csci.csusb.edu/dick/c++std/cd2/decl.html#dcl.fct
конкретно вот это:
3. <skip>
After determining the type of each parameter, any parameter of type "array of T" or "function returning T" is adjusted to be "pointer to T" or "pointer to function returning T," respectively.
Стандарт C++ подойдет?
http://www.csci.csusb.edu/dick/c++std/cd2/decl.html#dcl.array
Конкретно место:
Вот ещё наглядный пример:
заметь, не о каких указателях не говорится.
А вот про стандартное преобразование
http://www.csci.csusb.edu/dick/c++std/cd2/conv.html#conv.array
Конкретное место:
А здесь про преобразование в списке аргументов функции:
http://www.csci.csusb.edu/dick/c++std/cd2/decl.html#dcl.fct
конкретно вот это:
Всякий раз, когда в выражении появляется идентификатор типа массива, он преобразуется в указатель на первый член массива. Из-за преобразований массивы не являются адресами. По определению операция индексирования [] интерпретируется таким образом, что E1[E2] идентично *((E1)+(E2)). В силу правил преобразования, применяемых к +, если E1 массив и E2 целое, то E1[E2] относится к E2-ому члену E1. Поэтому, несмотря на такое проявление асимметрии, индексирование является коммутативной операцией.
Ты прав... Но для меня всё-таки "а" останится указателем на первый элемент, как раз из-за вышесказоного. Скорее пример с шаблоном и сайзеоф будет исключением (хотя всё наоборот), всёравно я не использую массивы.