Как получить «массив строк» ​​как тип возвращаемого значения функции? - PullRequest
2 голосов
/ 14 июня 2009

String [] decode (Строковое сообщение)

Выше приведен пример. Мне нужно получить 2 строки s1 и s2 в качестве возвращаемых значений для функции декодирования. Как мне поступить?

Ответы [ 9 ]

6 голосов
/ 14 июня 2009

Если вам нужно вернуть несколько строк, используйте одну из следующих:
- std :: pair
- boost :: tuple
- структура

Если вы не знаете, сколько строк возвратит ваша функция - используйте что-то вроде std :: vector.

4 голосов
/ 14 июня 2009

Я бы сказал, что есть варианты:

Для фиксированного количества строк:

1) вернуть пару, кортеж или структуру, которую вы определяете сами. Что-то вроде:

struct BrokenDownString {
    std::string firstbit;
    std::string middlebit;
    std::string endbit;
};

Тогда либо:

BrokenDownString decode(std::string message);

или просто предоставьте BrokenDownString конструктор, принимающий сообщение в качестве параметра.

2) Получить несколько выходных параметров по указателю или непостоянной ссылке:

void decode(const std::string &message, std::string &out_1, std::string &out_2) {
    out_1 = /*whatever*/;
    out_2 = /*whatever*/;
}

Для двух строк все остальное (даже массив) излишне.

Однако для переменного числа строк вы можете:

1) вернуть std::vector<std::string> (помните, что это может привести к избыточному копированию).

2) взять std::vector<std::string> & в качестве параметра и добавить результаты (это может копировать строки, но не контейнер).

3) сделать декодировать шаблон функции, принимая в качестве параметра выходной итератор:

template<typename OUT>
void decode(const std::string message, OUT out) {
    // do parsing
    *(out++) = firstbit;
    *(out++) = nextbit;
    // etc.
}

Тогда, если вызывающая сторона хочет получить результаты в векторе:

std::vector<std::string> v;
decode(message, std::back_inserter(v));

Если звонящий предпочитает их в деке:

std::deque<std::string> d;
decode(message, std::back_inserter(d));

Если звонящий хочет получить их в списке в обратном порядке:

std::list<std::string> l;
decode(message, std::front_inserter(l));

и т. Д.

4) Если вы хотите что-то подобное вышеописанному, но по какой-то причине вы не хотите писать код шаблона, сделайте decode take в качестве параметра объект, который он сообщает каждой строке:

struct DecodeTarget {
    virtual void append(const std::string &) = 0;
};

void decode(std::string message, DecodeTarget &out) {
    // do parsing
    out.append(firstbit);
    out.append(nextbit);
    // etc.
}

Тогда, если звонящий хочет получить результаты в векторе:

class VectorTarget : public DecodeTarget {
private:
    std::vector<std::string> &results;
public:
    VectorTarget(std::vector<std::string> &v) : results(v) { }
    void append(const std::string &bit) { v.push_back(bit); }
};

std::vector<std::string> v;
VectorTarget vt(v);
decode(message, vt);
4 голосов
/ 14 июня 2009

Если бы это был я, я бы вернул vector из string с. С массивом вам нужно беспокоиться об управлении памятью. Вы также можете передать строку как константную ссылку, если не хотите ее изменять.

1 голос
/ 14 июня 2009

Если вам абсолютно необходимо вернуть массив, вы можете использовать тот факт, что необработанные массивы распадаются на указатели. Вот пример кода, который делает то, что я думаю, что вы хотите:

#include <iostream>
#include <ostream>
#include <string>

std::string * decode()
{
    std::string *ret = new std::string[2];
    ret[0] = "foo";
    ret[1] = "bar";
    return ret;
}

int main()
{
    std::string *baz = decode();
    std::cout << baz[0] << baz[1] << std::endl;
    delete [] baz;

    return 0;
}

Обратите внимание, что этот способ требует, чтобы вы отслеживали следующее:

  • кому принадлежит память, возвращаемая decode()
  • тот факт, что возвращаемый указатель действительно является массивом
  • размер массива

Да, это больно. Вот почему все остальные предлагают использовать std::pair или std::vector для выполнения работы за вас.

1 голос
/ 14 июня 2009

Они (Top Coder) упоминали массив C-строк или массив std :: strings? К вашему сведению, массивы - это зло (http://siddhant3s.googlepages.com/how_to_tell_rusted_cpp.html и http://www.parashift.com/c++-faq-lite/containers.html#faq-34.1) В последнее время, если вы все еще хотите вернуть массив std :: strings, вы можете, но только если пообещаете мне, что удалите [] возвращенный указатель соответственно:

#include<iostream>
#include<string>
std::string* F1()
{
    std::string* s=new std::string[2];
    s[0]="Hello";
    s[1]="World";
    return s;
}

int main()
{
    std::string* ss=F1();
    std::cout<<ss[0]<<ss[1];

    delete[] ss; //important step
}
1 голос
/ 14 июня 2009

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

Однако, это очень подвержено ошибкам, поэтому вам, вероятно, следует придерживаться стандартного контейнера или класса строк.

0 голосов
/ 05 июля 2012

Вы можете:

Возвращает std::vector<std::string>, возвращает std::pair<std::string, std::string>, возвращает структуру со строками или, не возвращает, передает ссылку и устанавливает ее:

void decode(std::string & s1, std::string & s2, const std::string & otherParam) {
    // write the result to s1 and s2
}

Со ссылкой вы предотвратите ненужную копию.

0 голосов
/ 05 июля 2012

Я бы на самом деле не рекомендовал делать это таким образом для этого конкретного случая, но вы можете вернуть ссылку на массив строк:

std::string(& split_once(std::string arg))[]
    static std::string result[2];
    int i = arg.find_first_of('|');
    result[0] = arg.substr(0,i);
    result[1] = arg.substr(i + 1);
}

Это не очень подходит для данного конкретного приложения, но является допустимым способом возврата массива и полезно в других ситуациях. Я думаю, что даже использовал его где-то, хотя я не могу вспомнить, где и почему.

0 голосов
/ 14 июня 2009

Передайте строки в функции в виде параметров «out» - либо указателями, либо ссылками и измените их внутри функции.

...