Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

занятный тип string

7.8K
09 октября 2004 года
prankish_man
5 / / 09.10.2004
я, видимо, чего-то не понимаю, но при первых же попытках после перехода с Си на Си++ (MS Visual C++ 7) использовать класс string столкнулся с двумя совершенно неожиданными проблемами:
1. Не нашел подходящих функций преобразования целых чисел в тип string. Можно выйти из положения вот так:
 
Код:
char a[100];
str = ltoa(98, a, 10);

но ведь должен быть более красивый метод? Неужели нет стандартных функций (что-то типа IntToStr в Билдере?).

2. Почему-то при присвоении переменной типа string достаточно длинной строки сишного типа в string'е пишется всякая ахинея. Например, после выполнения этого кода в s1 будет ерунда:
 
Код:
char a[100];
  string s1;
  int n = 0;
  for (n = 0; n < 100; n++) {
    a[n] = '1';
  }
  a[99] = 0;
  s1 = a;
527
09 октября 2004 года
pavor
275 / / 28.09.2003
Цитата:
Originally posted by prankish_man
я, видимо, чего-то не понимаю, но при первых же попытках после перехода с Си на Си++ (MS Visual C++ 7) использовать класс string столкнулся с двумя совершенно неожиданными проблемами:
1. Не нашел подходящих функций преобразования целых чисел в тип string. Можно выйти из положения вот так:
 
Код:
char a[100];
str = ltoa(98, a, 10);

но ведь должен быть более красивый метод? Неужели нет стандартных функций (что-то типа IntToStr в Билдере?).

2. Почему-то при присвоении переменной типа string достаточно длинной строки сишного типа в string'е пишется всякая ахинея. Например, после выполнения этого кода в s1 будет ерунда:
 
Код:
char a[100];
  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

492
11 октября 2004 года
alibabaich
238 / / 08.07.2004
Цитата:
Originally posted by prankish_man


2. Почему-то при присвоении переменной типа string достаточно длинной строки сишного типа в string'е пишется всякая ахинея. Например, после выполнения этого кода в s1 будет ерунда:
 
Код:
char a[100];
  string s1;
  int n = 0;
  for (n = 0; n < 100; n++) {
    a[n] = '1';
  }
  a[99] = 0;
  s1 = a;


Всё логично. S1 это указатель на пустую строку а указатель на первый элемент масива типа чар. Кто же сказал укозателю типа стринг что нада ссылаться на весь масив а не на первый его элемент?

3
11 октября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by prankish_man
1. Не нашел подходящих функций преобразования целых чисел в тип string. Можно выйти из положения вот так:
 
Код:
char a[100];
str = ltoa(98, a, 10);

но ведь должен быть более красивый метод? Неужели нет стандартных функций (что-то типа IntToStr в Билдере?).


std::string - это класс из STL.
В стандарте С++ не сказано, что класс std::string должен содержать методы приведения из int. Это сделано в силу ряда причин.

Пожалуйста, красивые методы преобразований:

Код:
#include <string>
#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;
}


Цитата:
Originally posted by prankish_man
2. Почему-то при присвоении переменной типа string достаточно длинной строки сишного типа в string'е пишется всякая ахинея. Например, после выполнения этого кода в s1 будет ерунда:
 
Код:
char a[100];
  string s1;
  int n = 0;
  for (n = 0; n < 100; n++) {
    a[n] = '1';
  }
  a[99] = 0;
  s1 = a;


Да? А как ты проверял? :)
Скажу по секрету: все отлично работает, s1 отлично принял твой массив.
проверь добавив строчку
std::cout << s1;

Цитата:
Originally posted by prankish_man

Да, есть такое дело. По-моему в операторе = нет изменения размера string. Так что нужно сначала вызывать какой-нибудь preallocate.
Более красивых методов нет, есть только по-моему get buffer, release buffer, с помощью которых можно получать строки не меньшей длины, чем требуется.
Извини, но точные названия методов смотри в MSDN


Не надо ничего вызывать.
Как я уже и говорил, налицо отрицательное влияние С на С++.
Отвлекитесь от буферов, вы работаете с классом (инкапсуляция).

Цитата:
Originally posted by prankish_man

Всё логично. S1 это указатель на пустую строку а указатель на первый элемент масива типа чар. Кто же сказал укозателю типа стринг что нада ссылаться на весь масив а не на первый его элемент?


s1 - это не указатель, а экземпляр класса.
a[] - это тоже не указатель, а массив.
Про кто что кому сказал, вообще, бред какой-то.

492
11 октября 2004 года
alibabaich
238 / / 08.07.2004
s1 - это не указатель, а экземпляр класса.
a[] - это тоже не указатель, а массив.
Про кто что кому сказал, вообще, бред какой-то. [/QUOTE]

Про s1-полностью согласен, это хитрый указатель. Естественно это экземпляр класса.

a[] - массив. То же верно. А а? если это не указатель то что это? И что интересно произайдёт если:
 
Код:
char a[20];
char b;
b=a+10;
cout<<b<<endl;
3
11 октября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by alibabaich
Про s1-полностью согласен, это хитрый указатель. Естественно это экземпляр класса.


Это совсем не smart pointer.
Smart pointer подразумевает, что объект выглядит, как указатель (т.е. должен обладать интерфейсом указателя), а на самом деле является чем-то больше, т.е. обладает некоторой функциональностью. Smart pointer строится на операциях * и -> (operator *, operator ->).

std::string совсем не выглядит указателем.

Цитата:
Originally posted by alibabaich

a[] - массив. То же верно. А а? если это не указатель то что это? И что интересно произайдёт если:
 
Код:
char a[20];
char b;
b=a+10;
cout<<b<<endl;


a - это массив (кв.скобки я указал лишь для наглядности, имя переменной - a), а не указатель!
Хочешь убедиться?
Проверь: sizeof(a) == sizeof(char*)
Твой пример не скомпилируется, т.к. ты, видимо, допустил ошибку в определении b.
В исправленном примере

 
Код:
char a[20];
char* b;
b=a+10;
std::cout << b << std::endl;

произойдет следующее переменная a типа char[20] неявно приведется к указателю char*, далее произведется сложение и присвоение результата переменной b.
492
11 октября 2004 года
alibabaich
238 / / 08.07.2004
Цитата:
Originally posted by Green

Это совсем не smart pointer.
Smart pointer подразумевает, что объект выглядит, как указатель (т.е. должен обладать интерфейсом указателя), а на самом деле является чем-то больше, т.е. обладает некоторой функциональностью. Smart pointer строится на операциях * и -> (operator *, operator ->).

std::string совсем не выглядит указателем.



А запорожец не выглядит машиной. Но смысл от этого стринга не меняестя. Сокрытие реализации...

Цитата:
Originally posted by Green


a - это массив (кв.скобки я указал лишь для наглядности, имя переменной - a), а не указатель!
Хочешь убедиться?
Проверь: sizeof(a) == sizeof(char*)
Твой пример не скомпилируется, т.к. ты, видимо, допустил ошибку в определении b.
В исправленном примере
 
Код:
char a[20];
char* b;
b=a+10;
std::cout << b << std::endl;

произойдет следующее переменная a типа char[20] неявно приведется к указателю char*, далее произведется сложение и присвоение результата переменной b.


Да ошибка есть только не там, а: b = *(a+10) И если он приводится неявно к указателю на первый элемент массива, с какой стати стринг должен брать весь массив?

P.S. Приятно с вами Green спорить, много нового узнаю...

3
11 октября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by alibabaich

А запорожец не выглядит машиной. Но смысл от этого стринга не меняестя. Сокрытие реализации...


По твоему получается, что любой класс можно назвать "умным указателем" :)
"Умный указатель" потому и называется указателем, что им можно пользоваться как обычным указателем.
Вот несколько ссылок объясняющие, что такое 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.



Цитата:
Originally posted by alibabaich

Да ошибка есть только не там, а: b = *(a+10) И если он приводится неявно к указателю на первый элемент массива, с какой стати стринг должен брать весь массив?


Ну стандарт не полные идиоты писали...
Если оператору присваивания передается char*, то логично предположить, что передается строка символов, заканчивающаяся нулем. Поэтому в реализации класса string это и заложено.

std::string является специализацией класса std::basic_string:

 
Код:
typedef basic_string<char, char_traits<char>, allocator<char> >  string;

в этом классе такой оператор присваивания выглядит следующем образом:
 
Код:
_Myt& operator=(const _Elem *_Ptr)
{   // 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> это
 
Код:
static size_t __cdecl length(const _Elem *_First)
{   // find length of null-terminated string
    return (::strlen(_First));
}

Надеюсь, я доказал, что в реализацию std::string зашито восприятие char*, как символьной строки.
492
11 октября 2004 года
alibabaich
238 / / 08.07.2004
Цитата:
Originally posted by Green

По твоему получается, что любой класс можно назвать "умным указателем" :)
"Умный указатель" потому и называется указателем, что им можно пользоваться как обычным указателем.
Вот несколько ссылок объясняющие, что такое smart



Так чем запорожец от машины отличается? Я ж не спорю...

Цитата:
Originally posted by Green


Ну стандарт не полные идиоты писали...
Если оператору присваивания передается char*, то логично предположить, что передается строка символов, заканчивающаяся нулем. Поэтому в реализации класса string это и заложено.


И кто сказал про идиотов? Я это даже не подрозумевал... Если так выглядит прошу прощения... А char* это не строка, а указатель на числовой тип(ну не помню точно размерность 8 бит кажется или 16). И предполажение того что предоваться будет строка, не совсем верно. Я что уже не могу передать последовательность чисел не связаных со строкой?

3
11 октября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by alibabaich

Так чем запорожец от машины отличается?


Не знаю, я плохо в автомобилях разбираюсь... :)
У меня всегда Tayota были...

Цитата:
Originally posted by alibabaich

А char* это не строка, а указатель на числовой тип(ну не помню точно размерность 8 бит кажется или 16). И предполажение того что предоваться будет строка, не совсем верно.


В данном случае (std::string) лишь оно и верно.

Цитата:
Originally posted by alibabaich

Я что уже не могу передать последовательность чисел не связаных со строкой?


Можешь, но только не в классе std::string.
Можешь создать свой класс, в том числе на базе basic_string, только придется создать новый класс traits, либо переопределить оператор = в basic_string. Вот пример, как сделать, чтоб принимался только первый символ:

Код:
#include <iostream>
#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;
}
492
11 октября 2004 года
alibabaich
238 / / 08.07.2004
Цитата:
Originally posted by Green

У меня всегда Tayota были...


И после этого плохо разбираешься?:)

3
11 октября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by alibabaich

И после этого плохо разбираешься?:)


Реклама toyota не входит в суть этого топика... :D
Я ж к ним под капот один раз заглядывал,- при покупке... :D

492
11 октября 2004 года
alibabaich
238 / / 08.07.2004
Цитата:
Originally posted by Green

Реклама toyota не входит в суть этого топика... :D
Я ж к ним под капот один раз заглядывал,- при покупке... :D


Если а массив, то почему результат:

Код:
#include "stdafx.h"
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?
3
11 октября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by alibabaich

Если а массив, то почему результат:
Код:
#include "stdafx.h"
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)
{
    std::cout << sizeof(a) << std::endl;
}

void foo(char a[19])
{
    std::cout << sizeof(a) << std::endl;
}

то компилятор ругнется на то, что foo(char*) уже определен. Это говорит о том, что компилятор воспринимает char* и char[] в параметрах функции, как одно и тоже, т.е. неявно приводит char[] к char*. Сделано это, видимо, для совместимости с компиляторами С.

Теперь постараюсь передать массив без приведения.
Ссылки были введены в С++, и в С они отсутствуют.
Попробуем передать массив по ссылке, чтоб избежать неявного преобразования. Т.к. синтаксис не допускает указыавать ссылку при массиве, буду использовать шаблон:
Код:
#include <iostream>
#include <string>

template<typename T>
void foo(T&)
{
    std::cout << sizeof T << std::endl;
}

int main()
{
    char a[]="dlkghsdfjkllsdfjbv";
    foo(a);
    return 0;
}

Пишет 19. ЧТД :)
492
12 октября 2004 года
alibabaich
238 / / 08.07.2004
Цитата:
Originally posted by Green

Я думаю, это из за "дурной наследственности".
Опять же отрицательное влияние С на С++.


Ну, не надо про "дурное", сам же говорил что стандарт не идиоты придумали. Что дали с тем и работаем...

Цитата:
Originally posted by Green


Если написать так:
 
Код:
void foo(char* a)
{
    std::cout << sizeof(a) << std::endl;
}

void foo(char a[19])
{
    std::cout << sizeof(a) << std::endl;
}

то компилятор ругнется на то, что foo(char*) уже определен. Это говорит о том, что компилятор воспринимает char* и char[] в параметрах функции, как одно и тоже, т.е. неявно приводит char[] к char*. Сделано это, видимо, для совместимости с компиляторами С.


...Без коментариев.

Цитата:
Originally posted by Green



Теперь постараюсь передать массив без приведения.
Ссылки были введены в С++, и в С они отсутствуют.
Попробуем передать массив по ссылке, чтоб избежать неявного преобразования. Т.к. синтаксис не допускает указыавать ссылку при массиве, буду использовать шаблон:
Код:
#include <iostream>
#include <string>

template<typename T>
void foo(T&)
{
    std::cout << sizeof T << std::endl;
}

int main()
{
    char a[]="dlkghsdfjkllsdfjbv";
    foo(a);
    return 0;
}

Пишет 19. ЧТД :)


Может так оно и есть... А может и нет. Буду копать в литературе, найду напишу, пока буду придерживаться твоей точки зрения....

3
12 октября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by alibabaich

Может так оно и есть... А может и нет. Буду копать в литературе, найду напишу, пока буду придерживаться твоей точки зрения....



Стандарт 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

Конкретное место:

 
Код:
1 An lvalue of type "array of N T" or "array of unknown bound of T"  can be  converted  to  an rvalue of type "pointer to T."  The result is a pointer to the first element of the 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.

492
12 октября 2004 года
alibabaich
238 / / 08.07.2004
Цитата:
Originally posted by Green


Стандарт 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

Конкретное место:
 
Код:
1 An lvalue of type "array of N T" or "array of unknown bound of T"  can be  converted  to  an rvalue of type "pointer to T."  The result is a pointer to the first element of the array.


А здесь про преобразование в списке аргументов функции:
http://www.csci.csusb.edu/dick/c++std/cd2/decl.html#dcl.fct
конкретно вот это:



Всякий раз, когда в выражении появляется идентификатор типа массива, он преобразуется в указатель на первый член массива. Из-за преобразований массивы не являются адресами. По определению операция индексирования [] интерпретируется таким образом, что E1[E2] идентично *((E1)+(E2)). В силу правил преобразования, применяемых к +, если E1 массив и E2 целое, то E1[E2] относится к E2-ому члену E1. Поэтому, несмотря на такое проявление асимметрии, индексирование является коммутативной операцией.

Ты прав... Но для меня всё-таки "а" останится указателем на первый элемент, как раз из-за вышесказоного. Скорее пример с шаблоном и сайзеоф будет исключением (хотя всё наоборот), всёравно я не использую массивы.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог