Re: как std::vector<const std::string> передать как char** ?
От: Bell Россия  
Дата: 11.04.08 09:24
Оценка: 1 (1)
Здравствуйте, szag, Вы писали:


#include <string>
#include <vector>
#include <algorithm>

typedef std::string str;
typedef std::vector<str> StrContainer;

static const str s1 = "11";
static const str s2 = "22";
static const str s3 = "33";
static const str s4 = "44";

void f(char** p, int i)
{
for (int k = 0; k < i; ++k)
std::cout << p[k] << std::endl;
}


int main()
{
StrContainer vec;

vec.push_back(s1);
vec.push_back(s2);
vec.push_back(s3);
vec.push_back(s4);

std::vector<const char*> ptr_array(vec.size());
std::transform(vec.begin(), vec.end(), ptr_array.begin(), std::mem_fun_ref(&std::string::c_str));


f(const_cast<char**>(&ptr_array[0]), vec.size());

return 0;
}
Любите книгу — источник знаний (с) М.Горький
как std::vector<const std::string> передать как char** ?
От: szag  
Дата: 11.04.08 09:04
Оценка:
#include <iostream>
#include <string>
#include <vector>

typedef std::string str;
typedef std::vector<const str> StrContainer;

static const str s1 = "11";
static const str s2 = "22";
static const str s3 = "33";
static const str s4 = "44";

void f(char** p, int i)
{
for (int k = 0; k < i; ++k)
std::cout << p[k] << std::endl;
}


int main()
{
StrContainer vec;

vec.push_back(s1);
vec.push_back(s2);
vec.push_back(s3);
vec.push_back(s4);

// f(что-то , vec.size())

return 0;
}

собственно вот пример програмки, в реальном жизни функция f находится в сторонней библиотеке и править её нет никакой возможности. Как сделать чтобы заработало?
Re[2]: как std::vector<const std::string> передать как char*
От: K13 http://akvis.com
Дата: 11.04.08 09:37
Оценка:
B>std::vector<const char*> ptr_array(vec.size());
B>std::transform(vec.begin(), vec.end(), ptr_array.begin(), std::mem_fun_ref(&std::string::c_str));


ИМХО рискованно. Нет никакой гарантии на время жизни указателя, возвращаемого c_str(), за пределами текущего оператора.
Надежнее копировать через сами строки во временный буфер выставляя указатели (если не конечно этот кусок не bottleneck)
Re[2]: как std::vector<const std::string> передать как char*
От: Кодт Россия  
Дата: 11.04.08 09:40
Оценка:
Здравствуйте, Bell, Вы писали:

Может, вместо
B>f(const_cast<char**>(&ptr_array[0]), vec.size());

переделать функцию
B>void f(char const* /*const*/ * p, int i)

А то, мало ли, что ей внутри взбредёт в голову?
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[3]: как std::vector<const std::string> передать как char*
От: Bell Россия  
Дата: 11.04.08 09:45
Оценка:
Здравствуйте, K13, Вы писали:

K13>
B>>std::vector<const char*> ptr_array(vec.size());
B>>std::transform(vec.begin(), vec.end(), ptr_array.begin(), std::mem_fun_ref(&std::string::c_str));
K13>


K13>ИМХО рискованно. Нет никакой гарантии на время жизни указателя, возвращаемого c_str(), за пределами текущего оператора.

Если бы это было так, то практическая ценность c_str равнялась бы нулю:

21.3.6 basic_string string operations

const charT* c_str() const;

1 Returns: A pointer to the initial element of an array of length size() + 1 whose first size() elements
equal the corresponding elements of the string controlled by *this and whose last element is a
null character specified by charT().
2 Requires: The program shall not alter any of the values stored in the array. Nor shall the program treat the
returned value as a valid pointer value after any subsequent call to a non-const member function of the
class basic_string that designates the same object as this.


Так что до тех пор, пока объект не трогают (не вызывают неконстантные методы), указатель, возвращенный c_str, валиден.

Опасность тут в другом — приходится снимать константность с указетелей.

K13>Надежнее копировать через сами строки во временный буфер выставляя указатели (если не конечно этот кусок не bottleneck)

Безусловно это надежней, но и затратней.
Любите книгу — источник знаний (с) М.Горький
Re[3]: как std::vector<const std::string> передать как char*
От: Bell Россия  
Дата: 11.04.08 09:47
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Bell, Вы писали:


К>Может, вместо

К>
B>>f(const_cast<char**>(&ptr_array[0]), vec.size());
К>

К>переделать функцию
К>
B>>void f(char const* /*const*/ * p, int i)
К>

К>А то, мало ли, что ей внутри взбредёт в голову?

Само собой лучше! Но в условии было:

... функция f находится в сторонней библиотеке и править её нет никакой возможности.


А так переделали бы ее на прием пары итераторов — да и дело с концом
Любите книгу — источник знаний (с) М.Горький
Re: как std::vector<const std::string> передать как char** ?
От: rg45 СССР  
Дата: 11.04.08 10:07
Оценка:
Здравствуйте, szag, Вы писали:

А тебе действительно нужен доступ к константым данным как к неконстантым, или ты просто забыл написать модификатор const в параметре функции f?
Исходя из задачи, решаемой в примере, его лучше бы переписать как-то так:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>

const std::string vec_content[] = {"11", "22", "33", "44"};
const int vec_content_size = sizeof(vec_content)/sizeof(*vec_content);

void f(const char** p, size_t i)
{
  for (size_t k = 0; k < i; ++k)
    std::cout << p[k] << std::endl;
}

int main()
{
  std::vector<std::string> vec(vec_content, vec_content + vec_content_size);

  std::vector<const char*> pointers(vec.size());
  transform(vec.begin(), vec.end(), pointers.begin(), mem_fun_ref(&std::string::c_str));
  f(&pointers.front(), pointers.size()); 
}
... << RSDN@Home 1.2.0 alpha rev. 787>>
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: как std::vector<const std::string> передать как char*
От: szag  
Дата: 11.04.08 11:15
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здравствуйте, szag, Вы писали:



B>
B>#include <string>
B>#include <vector>
B>#include <algorithm>

B>typedef std::string str;
B>typedef std::vector<str> StrContainer;

B>static const str s1 = "11";
B>static const str s2 = "22";
B>static const str s3 = "33";
B>static const str s4 = "44";

B>void f(char** p, int i)
B>{
B>for (int k = 0; k < i; ++k)
B>std::cout << p[k] << std::endl;
B>}


B>int main()
B>{
B>StrContainer vec;

B>vec.push_back(s1);
B>vec.push_back(s2);
B>vec.push_back(s3);
B>vec.push_back(s4);

B>std::vector<const char*> ptr_array(vec.size());
B>std::transform(vec.begin(), vec.end(), ptr_array.begin(), std::mem_fun_ref(&std::string::c_str));


B>f(const_cast<char**>(&ptr_array[0]), vec.size());

B>return 0;
B>}
B>



Спасибо, помогло. Только надо еще один инклуд добавить, но это уже мелочи
#include <functional>
Re[2]: как std::vector<const std::string> передать как char*
От: szag  
Дата: 11.04.08 11:21
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, szag, Вы писали:


R>А тебе действительно нужен доступ к константым данным как к неконстантым, или ты просто забыл написать модификатор const в параметре функции f?

R>Исходя из задачи, решаемой в примере, его лучше бы переписать как-то так:
R>
R>#include <iostream>
R>#include <string>
R>#include <vector>
R>#include <algorithm>
R>#include <functional>

R>const std::string vec_content[] = {"11", "22", "33", "44"};
R>const int vec_content_size = sizeof(vec_content)/sizeof(*vec_content);

R>void f(const char** p, size_t i)
R>{
R>  for (size_t k = 0; k < i; ++k)
R>    std::cout << p[k] << std::endl;
R>}

R>int main()
R>{
R>  std::vector<std::string> vec(vec_content, vec_content + vec_content_size);

R>  std::vector<const char*> pointers(vec.size());
R>  transform(vec.begin(), vec.end(), pointers.begin(), mem_fun_ref(&std::string::c_str));
R>  f(&pointers.front(), pointers.size()); 
R>}
R>


Нет, функцию f править нельзя. Я просто написал пример, на самом деле список строк формируется на этапе выполнения и заранее он не известен.
Re[3]: как std::vector<const std::string> передать как char*
От: rg45 СССР  
Дата: 11.04.08 11:39
Оценка:
Здравствуйте, szag, Вы писали:

S>Нет, функцию f править нельзя. Я просто написал пример, на самом деле список строк формируется на этапе выполнения и заранее он не известен.


Понятно. В таком случае, надо отдавать себе отчет, что такая огрганизация чревата: изначально имеем константные данные, реинтерпретируем их как неконстантные, оправдывая этим, что так надо для конкретной функции, что сама по себе эта функция проверенная и никакого вреда не причинит... Но проходит время, таких опасных мест становится все больше, к проекту подключаются новые люди, и потом бац! в один прекрасный момент выясняется, что наш проект уже как пол года неработоспособен, в чем корень зла никто не знает, и в ночь с пятницы на понедельник мы в муках ищем заплату на эту дырку, потому, что в понедельник кровь из носу должен быть релиз.
... << RSDN@Home 1.2.0 alpha rev. 787>>
--
Справедливость выше закона. А человечность выше справедливости.
Re[4]: как std::vector<const std::string> передать как char*
От: szag  
Дата: 11.04.08 13:10
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, szag, Вы писали:


S>>Нет, функцию f править нельзя. Я просто написал пример, на самом деле список строк формируется на этапе выполнения и заранее он не известен.


R>Понятно. В таком случае, надо отдавать себе отчет, что такая огрганизация чревата: изначально имеем константные данные, реинтерпретируем их как неконстантные, оправдывая этим, что так надо для конкретной функции, что сама по себе эта функция проверенная и никакого вреда не причинит... Но проходит время, таких опасных мест становится все больше, к проекту подключаются новые люди, и потом бац! в один прекрасный момент выясняется, что наш проект уже как пол года неработоспособен, в чем корень зла никто не знает, и в ночь с пятницы на понедельник мы в муках ищем заплату на эту дырку, потому, что в понедельник кровь из носу должен быть релиз.


Вы абсолютно правы. Но у меня просто нет выбора. Эта функция (f) копирует эти строки себе внутри себя и больше никак передаваемый массив не использует. Почему сделали на вход char** а не const char** я не знаю.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.