Почему я не могу присвоить скалярную величину классу с помощью стенографии, но вместо этого объявить это сначала, затем установить ее значение?

Я пишу библиотеку UTF-8 для C++ как осуществление, поскольку это - мой первый реальный код C++. До сих пор я реализовал конкатенацию, символьную индексацию, парсинг и кодирование UTF-8 в классе, названном "ustring". Похоже, что это работает, но два на вид эквивалентных способа объявить новый ustring ведут себя по-другому. Первый путь:

ustring a;
a = "test";

работы и перегруженное "=" оператор анализирует строку в класс (который хранит строки Unicode как динамично выделенный международный указатель). Однако следующее не работает:

ustring a = "test";

потому что я получаю следующую ошибку:

test.cpp:4: error: conversion from ‘const char [5]’ to non-scalar type ‘ustring’ requested

Существует ли путь к обходному решению эта ошибка? Это, вероятно - проблема с моим кодом, все же. Следующее - то, что я записал до сих пор для библиотеки:

#include <cstdlib>
#include <cstring>
class ustring {
  int * values;
  long len;
  public:
  long length() {
    return len;
  }
  ustring * operator=(ustring input) {
    len = input.len;
    values = (int *) malloc(sizeof(int) * len);
    for (long i = 0; i < len; i++)
      values[i] = input.values[i];
    return this;
  }
  ustring * operator=(char input[]) {
    len = sizeof(input);
    values = (int *) malloc(0);
    long s = 0;                                                                 // s = number of parsed chars
    int a, b, c, d, contNeed = 0, cont = 0;
    for (long i = 0; i < sizeof(input); i++)
      if (input[i] < 0x80) {                                                    // ASCII, direct copy (00-7f)
        values = (int *) realloc(values, sizeof(int) * ++s);
        values[s - 1] = input[i];
      } else if (input[i] < 0xc0) {                                             // this is a continuation (80-bf)
        if (cont == contNeed) {                                                 // no need for continuation, use U+fffd
          values = (int *) realloc(values, sizeof(int) * ++s);
          values[s - 1] = 0xfffd;
        }
        cont = cont + 1;
        values[s - 1] = values[s - 1] | ((input[i] & 0x3f) << ((contNeed - cont) * 6));
        if (cont == contNeed) cont = contNeed = 0;
      } else if (input[i] < 0xc2) {                                             // invalid byte, use U+fffd (c0-c1)
        values = (int *) realloc(values, sizeof(int) * ++s);
        values[s - 1] = 0xfffd;
      } else if (input[i] < 0xe0) {                                             // start of 2-byte sequence (c2-df)
        contNeed = 1;
        values = (int *) realloc(values, sizeof(int) * ++s);
        values[s - 1] = (input[i] & 0x1f) << 6;
      } else if (input[i] < 0xf0) {                                             // start of 3-byte sequence (e0-ef)
        contNeed = 2;
        values = (int *) realloc(values, sizeof(int) * ++s);
        values[s - 1] = (input[i] & 0x0f) << 12;
      } else if (input[i] < 0xf5) {                                             // start of 4-byte sequence (f0-f4)
        contNeed = 3;
        values = (int *) realloc(values, sizeof(int) * ++s);
        values[s - 1] = (input[i] & 0x07) << 18;
      } else {                                                                  // restricted or invalid (f5-ff)
        values = (int *) realloc(values, sizeof(int) * ++s);
        values[s - 1] = 0xfffd;
      }
    return this;
  }
  ustring operator+(ustring input) {
    ustring result;
    result.len = len + input.len;
    result.values = (int *) malloc(sizeof(int) * result.len);
    for (long i = 0; i < len; i++)
      result.values[i] = values[i];
    for (long i = 0; i < input.len; i++)
      result.values[i + len] = input.values[i];
    return result;
  }
  ustring operator[](long index) {
    ustring result;
    result.len = 1;
    result.values = (int *) malloc(sizeof(int));
    result.values[0] = values[index];
    return result;
  }
  char * encode() {
    char * r = (char *) malloc(0);
    long s = 0;
    for (long i = 0; i < len; i++) {
      if (values[i] < 0x80)
        r = (char *) realloc(r, s + 1),
        r[s + 0] = char(values[i]),
        s += 1;
      else if (values[i] < 0x800)
        r = (char *) realloc(r, s + 2),
        r[s + 0] = char(values[i] >> 6 | 0x60),
        r[s + 1] = char(values[i] & 0x3f | 0x80),
        s += 2;
      else if (values[i] < 0x10000)
        r = (char *) realloc(r, s + 3),
        r[s + 0] = char(values[i] >> 12 | 0xe0),
        r[s + 1] = char(values[i] >> 6 & 0x3f | 0x80),
        r[s + 2] = char(values[i] & 0x3f | 0x80),
        s += 3;
      else
        r = (char *) realloc(r, s + 4),
        r[s + 0] = char(values[i] >> 18 | 0xf0),
        r[s + 1] = char(values[i] >> 12 & 0x3f | 0x80),
        r[s + 2] = char(values[i] >> 6 & 0x3f | 0x80),
        r[s + 3] = char(values[i] & 0x3f | 0x80),
        s += 4;
    }
    return r;
  }
};
5
задан Brian Tompsett - 汤莱恩 27 November 2015 в 15:44
поделиться

2 ответа

Ваша проблема в том, что ustring a = "test" фактически вызывает конструктор, а не оператор присваивания. ура, добро пожаловать в c++ :)

Вам нужно определить себе как конструктор по умолчанию, так и тот, который принимает const char*, потому что как только вы определите a конструктор, вам нужно будет определить все ваши конструкторы.

Несколько других вещей:

  • передавайте входную строку по ссылке
  • передавайте const char * вместо char[] (вы не изменяете входные данные и char* более распространен)
  • sizeof делает не то, что вы думаете, он не работает правильно для параметров массива. Она возвращает вам sizeof(char*), а не sizeof(array).
  • возвращайте ссылку на this из ваших операторов.
  • вы можете использовать vector values;, чтобы управлять всей вашей памятью за вас.
  • encode(), вероятно, должна возвращать string. С string
    • она сама управляет своей памятью, поэтому вызывающей стороне не нужно освобождать или удалять ее.
    • вы можете использовать s.append(c); вместо realloc.
    • вы можете использовать printf("%s", s.c_str());, но в c++ обычно используется cout << s;
  • рассмотрим также определение конструктора копирования.

Например, так:

class ustring {
 public:
  // Default constructor, allows you to create your class with no arguments.
  ustring() { ...; }
  // Allows you to create your class from string literals.
  ustring(const char *input) { ...; }
  // Copy constructor, allows you to create your class from other instances.
  ustring(const ustring &input) { ...; }

  // Assignment operators.
  ustring &operator=(const ustring &input) { ...; return *this; }
  ustring &operator=(const char *input) { ...; return *this; }
};

int main() {
  ustring s, t;  // invokes default constructor.
  s = t;         // invokes ustring assignment op.
  s = "test";    // invokes const char* assignment op.
  ustring u = "test";  // invokes const char* constructor.
  ustring v("test");   // invokes const char* constructor.
  ustring x(u);  // invokes copy constructor.
}

Если это c++, зачем вы делаете все эти malloc/realloc? Я не полностью разобрал этот код, но я предполагаю, что есть более простой способ... см. комментарий об использовании вектора.

Как отметил в комментариях @Michael Aaron Safyan, если вы выделяете память для класса ustring, вы захотите деаллоцировать ее в деструкторе. Однако я думаю, что, перейдя на контейнеры с управлением памятью - vector & string - вы избежите любого собственного управления памятью и сможете избежать написания деструктора.

16
ответ дан 18 December 2019 в 09:48
поделиться

Это две операции:

ustring a; // construct a new object using constructor
a = "test"; // assign value to object using operator=

Это одна операция:

ustring a = "test"; // construct with a value, aka value-intialization

В интересах эффективности времени выполнения и обеспечения семантической свободы C ++ не экстраполирует конструктор по умолчанию ustring :: ustring () и оператор присваивания ustring :: operator = (const char *) в конструктор ustring :: ustring (const char *) .

Но для большинства разумных строковых классов это будет работать:

ustring::ustring(const char *str)
 : /* initialize ustring::ustring() does */ {
    /* do whatever ustring::ustring() does */
    *this = str; // assign value.
}

Лучше вызвать оператор присваивания из конструктора, чем пытаться сделать наоборот.

Конечно, вы, вероятно, можете повысить эффективность, учитывая длину данной строки при выполнении инициализации.

1
ответ дан 18 December 2019 в 09:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: