【问题标题】:Custom String Deficiency自定义字符串不足
【发布时间】:2015-08-07 11:10:01
【问题描述】:

所以我目前的问题是,当我与修改后的字符串值和未修改的字符串值进行比较时,我没有得到 true 的预期结果,而是 >假。我已经重载了逻辑比较运算符,但这不是我想要做的,这无助于解决我的答案,但它确实有效,但是当我在 std::map 中使用它时它不会不行。

编辑:我需要知道的是 std::map 使用什么来通过迭代对两个对象进行逻辑比较。

String.h

#pragma once

#include <iostream>
#include <string>
#include <vector>

enum Pos
{
    BEGINNING,
    ENDING
};

class String
{
public:
    char *chars;

    String();
    String(char *chars);
    String(const char *chars);
    String(unsigned int size);

    unsigned int Length();
    String SubStr(unsigned int start, unsigned int end);
    String SubStr(unsigned int start);
    unsigned int HasStr(const char *chars);
    unsigned int HasStrInv(const char *chars);
    int FindFirst(const char *chars, Pos pos);
    int FindLast(const char *chars, Pos pos);
    std::vector<String> Split(const char *delimeter);

    String operator+(const char *chars);
    String operator=(const char *chars);
    String operator+=(const char *chars);
    bool operator==(const char *chars);
    bool operator==(String str);
    operator char*();

    static bool Equals(const char *a, const char *b);
    static unsigned int Length(const char *chars);
    static String Concate(const char *a, const char *b);
};

String operator+(const char *a, String b);
bool operator==(const char *a, String b);

String.cpp

#include "String.h"

String::String()
    : chars("")
{
}

String::String(char *chars)
{
    this->chars = chars;
}

String::String(const char *chars)
{
    this->chars = const_cast<char *>(chars);
}

String::String(unsigned int size)
{
    chars = new char[size];
}

unsigned int String::Length()
{
    return Length(chars);
}

String String::SubStr(unsigned int start, unsigned int end)
{
    unsigned int size = ((++end) - start) + 1;
    char *buffer = new char[size];
    for (unsigned int i = start; i < end; i++)
    {
        buffer[i - start] = chars[i];
    }
    buffer[size - 1] = '\0';
    return String(buffer);
}

String String::SubStr(unsigned int start)
{
    unsigned int size = (Length() - start);
    char *buffer = new char[size];
    for (unsigned int i = start; i < Length(); i++)
    {
        buffer[i - start] = chars[i];
    }
    buffer[size] = '\0';
    return String(buffer);
}

unsigned int String::HasStr(const char * chars)
{
    unsigned int d = 0, count = 0;
    for (unsigned int i = 0; i < strlen(this->chars); ++i)
    {
        if (this->chars[i] == chars[d])
        {
            ++d;
            if (d >= strlen(chars))
            {
                ++count;
                d = 0;
            }
        }
        else
        {
            d = 0;
        }
    }
    return count;
}

unsigned int String::HasStrInv(const char * chars)
{
    bool greater = false;
    unsigned int i, d = 0, start = 0, count = 0;
    for (i = 0; i < Length(); ++i)
    {
        if (this->chars[i] == chars[d])
        {
            d++;
            if (d >= strlen(chars))
            {
                if (greater)
                {
                    greater = false;
                    ++count;
                }
                start = i + 1;
                d = 0;
            }
        }
        else
        {
            greater = true;
            d = 0;
        }
    }
    if (start - 1 < Length() - 1)
    {
        ++count;
    }

    return count;
}

int String::FindFirst(const char * chars, Pos pos)
{
    unsigned int d = 0;
    for (unsigned int i = 0; i < strlen(this->chars); ++i)
    {
        if (this->chars[i] == chars[d])
        {
            ++d;
            if (d >= strlen(chars))
            {
                switch (pos)
                {
                case Pos::BEGINNING:
                    return i - (strlen(chars) - 1);
                    break;
                case Pos::ENDING:
                    return i;
                    break;
                }
            }
        }
        else
        {
            d = 0;
        }
    }
    return -1;
}

int String::FindLast(const char * chars, Pos pos)
{
    unsigned int d = strlen(chars) - 1;
    for (unsigned int i = strlen(this->chars); i > 0; --i)
    {
        if (this->chars[i] == chars[d])
        {
            --d;
            if (d >= strlen(chars))
            {
                switch (pos)
                {
                case Pos::BEGINNING:
                    return i;
                case Pos::ENDING:
                    return i + (strlen(chars) - 1);
                }
            }
        }
        else
        {
            d = strlen(chars) - 1;
        }
    }
    return -1;
}

std::vector<String> String::Split(const char *delimeter)
{
    unsigned int size = HasStrInv(delimeter);
    std::vector<String> buffer(size);

    bool greater = false;
    unsigned int i, d = 0, start = 0, count = 0;
    for (i = 0; i < Length(); ++i)
    {
        if (this->chars[i] == delimeter[d])
        {
            d++;
            if (d >= strlen(delimeter))
            {
                if (greater)
                {
                    greater = false;
                    buffer[count++] = SubStr(start, i - strlen(delimeter));
                }
                start = i + 1;
                d = 0;
            }
        }
        else
        {
            greater = true;
            d = 0;
        }
    }
    if (start - 1 < Length() - 1)
    {
        buffer[count] = SubStr(start, Length() - 1);
    }
    return buffer;
}

String String::operator+(const char *chars)
{
    return Concate(this->chars, chars);
}

String String::operator=(const char *chars)
{
    this->chars = const_cast<char *>(chars);
    return *this;
}

String String::operator+=(const char * chars)
{
    this->chars = Concate(this->chars, chars);
    return *this;
}

bool String::operator==(const char * chars)
{
    return Equals(this->chars, chars);
}

bool String::operator==(String str)
{
    return Equals(chars, str);
}

String::operator char*()
{
    return chars;
}

bool String::Equals(const char *a, const char *b)
{
    if (Length(a) == Length(b))
    {
        for (unsigned int i = 0; i < Length(a); ++i)
        {
            if (a[i] != b[i])
                return false;
        }
        return true;
    }
    return false;
}

unsigned int String::Length(const char * chars)
{
    unsigned int i = 0;
    while (chars[i] != '\0')
    {
        ++i;
    }
    return i;
}

String String::Concate(const char *a, const char *b)
{
    unsigned int size = strlen(a) + strlen(b) + 1;
    char *buffer = new char[size];
    for (unsigned int i = 0; i < strlen(a); ++i)
    {
        buffer[i] = a[i];
    }
    for (unsigned int i = strlen(a); i < size - 1; ++i)
    {
        buffer[i] = b[i - strlen(a)];
    }
    buffer[size - 1] = '\0';
    return String(buffer);
}

String operator+(const char *a, String b)
{
    return String::Concate(a, b);
}

bool operator==(const char *a, String b)
{
    return String::Equals(a, b);
}

示例修改

#include <iostream>
#include "String.h"

int main(int argc, char *argv[])
{
    String s = "Textures/SpaceShip.png";
    String a = s.SubStr(s.FindLast("/", Pos::ENDING) + 1);

    if (a.chars == "SpaceShip.png")
    {
        std::cout << "Equals" << std::endl;
    }
    else
    {
        std::cout << "Not Equals" << std::endl;
    }

    return 0;
}

输出

Not Equals

未修改示例

#include <iostream>
#include "String.h"

int main(int argc, char *argv[])
{
    String s = "Textures/SpaceShip.png";
    String a = "Textures/SpaceShip.png";

    if (s.chars == a.chars)
    {
        std::cout << "Equals" << std::endl;
    }
    else
    {
        std::cout << "Not Equals" << std::endl;
    }

    return 0;
}

输出

Equals

TextureManager.cpp

#include "TextureManager.h"

std::map<char *, Texture2D> TextureManager::textures;

Texture2D * TextureManager::GetTexture(String path)
{
    auto it = textures.find(path);
    if (it == textures.end())
        throw new std::exception("LWE: Texture not found. " + path);
    return &it->second;
}

void TextureManager::DeleteTexture(String path)
{
    auto it = textures.find(path);
    if (it == textures.end())
        throw new std::exception("LWE: Texture not found. " + path);
    glDeleteTextures(1, &it->second.id);
    textures.erase(it);
}

void TextureManager::InsertTexture2D_PNG(String filePath)
{
    Texture2D texture;
    std::vector<unsigned char> data;

    FileInfo fi = IOManager::ReadFile(filePath);

    if (decodePNG(data, texture.width, texture.height, (unsigned char *)fi.data, fi.size, true) != 0)
        throw new std::exception("Failed to decode png." + filePath);

    glGenTextures(1, &texture.id);
    glBindTexture(GL_TEXTURE_2D, texture.id);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glGenerateMipmap(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 0);

    textures.insert(std::make_pair(filePath.SubStr(filePath.FindLast("/", Pos::ENDING) + 1), texture));
}

【问题讨论】:

  • 我想你的意思是if(s == a)
  • 我试图避免这样做。使用重载对 std::map 没有帮助。
  • 在您的示例中,您将 char* 与不相等的 char* 进行比较,除非它们都指向同一个地址......或者我只是感到困惑?
  • 添加了另一个未修改版本的示例。对于任何正在寻找的人,我建议您查看 SubStr 方法。
  • @Red-XIII 为什么对std::map 没有帮助? std::map 使用 a == b,而不是 a.chars == b.chars

标签: c++ string char comparison


【解决方案1】:

std::map 不使用operator == 它使用operator &lt;。您需要实现该运算符才能使用您的 String 类型作为映射的键。

这里是一个例子——注意参数和函数的const——这是std::map所要求的。在这种情况下,这意味着您还需要将Length 更改为const

bool String::operator < (const String &str) const
{
    unsigned int myLength = Length();
    unsigned int strLength = str.Length();

    for (unsigned int i = 0; i < myLength && i < strLength; i++)
    {
        if (chars[i] < str.chars[i])
            return true;
        else if (chars[i] > str.chars[i])
            return false;
    }

    if (myLength < strLength)
        return true;

    return false;
}

并使用它:

std::map<String, int> myMap;

myMap["abc"]++;
myMap["abc"]++;
myMap["def"]++;

for (auto & entry : myMap)
{
    std::cout << entry.first.chars << ":" << entry.second << std::endl;
}

【讨论】:

  • 你太棒了!这正是我一直在寻找的。 +1 为例。 Nvm 我不能给代表。
  • 怎么样?您是否收到错误消息,或者它的行为与预期不符?
  • 好的,我对这个问题做了更多的调试。如果我在不使用 SubStr 的情况下执行此操作,它会非常好,但是如果我这样做,它有永远找不到值的趋势。
  • 您能否展示您正在尝试的代码 - 它们可能是 &lt; 运算符中的一些错误 - 我没有对其进行广泛测试。也许把它作为你问题的补充。
  • 完成,公平警告其中有一些 OpenGL 上下文。
【解决方案2】:

您不能使用 (s.chars == a.chars) 比较两个字符串,它比较两个指针的地址,并且对于两个不同的字符串对象总是返回 false。

【讨论】:

  • 是的,我最近才发现,不过感谢您的宝贵时间。不幸的是,这仍然不能解决我的错误。
  • 我需要知道的是 std::map 使用什么来通过迭代对两个对象进行逻辑比较。
  • 您还有其他问题,通常 String(const char *chars) 会复制字符,而不是获取其地址。
猜你喜欢
  • 2012-07-19
  • 2019-06-02
  • 1970-01-01
  • 2013-08-09
  • 2023-03-11
  • 2011-02-20
  • 2012-08-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多