小编Chr*_*sMM的帖子

使用 C++20 概念为自定义容器创建迭代器

C++20 引入了概念,这是一种对模板函数或类可以采用的类型施加约束的智能方法。

虽然迭代器类别和属性保持不变,但改变的是执行它们的方式:C++17 之前使用标记,C++20 以来使用概念。例如,您可以使用 std::forward_iterator 概念来标记迭代器,而不是使用 std::forward_iterator_tag 标签。

同样的事情也适用于所有迭代器属性。例如,前向迭代器必须是 std::incrementable。这种新机制有助于获得更好的迭代器定义,并使编译器中的错误更具可读性。

这段文字摘自这篇文章: https ://www.internalpointers.com/post/writing-custom-iterators-modern-cpp

但作者并没有升级如何用概念在C++20上制作自定义迭代器的内容,仍然是<= C++17标签版本。

有人可以举例说明如何使用概念功能在 C++20 版本中为自定义容器编写自定义迭代器吗?

c++ c++-concepts c++20

19
推荐指数
1
解决办法
5417
查看次数

如何确定要包括的头文件?

说我有以下(非常简单)的代码。

#include <iostream>
int main() {
    std::cout << std::stoi("12");
}
Run Code Online (Sandbox Code Playgroud)

这在g ++和clang上都可以编译。但是,它无法在MSVC上编译,并出现以下错误:

错误C2039:“ stoi”:不是“ std”的成员

错误C3861:“ stoi”:找不到标识符

我知道这std::stoi<string>标头的一部分,大概前两个编译器作为标头的一部分<iostream>而后者不包含。根据C ++标准[res.on.headers]

C ++标头可以包括其他C ++标头。

对我来说,这基本上说所有三个编译器都是正确的。

当我的一个学生提交作业时,这个问题就出现了,TA标记为未编译。我当然去修理了。但是,我想防止将来发生此类事件。因此,有没有一种方法可以确定应该包括哪些头文件,而无需在每次检查的三个不同编译器上进行编译?

我能想到的唯一方法是确保对于每个std函数调用都存在一个适当的include。但是,如果您现有的代码长数千行,则搜索起来可能很乏味。有没有更简单/更好的方法来确保交叉编译器的兼容性?

三种编译器的示例:https : //godbolt.org/z/kJhS6U

c++

9
推荐指数
1
解决办法
314
查看次数

如何防止修改数组数据?

假设我有一个看起来像这样的类(这只是一个例子):

class A {
    double *ptr;
public:
    A() : ptr( new double[100] ) {}
    A( const A &other ) {
        other.ptr[7] = 15;
    }
    void doNotChangeMyData() const {
        ptr[43] = 14;
    }
    void changeMyData() {
        ptr[43] = 14;
    }
    ~A() { delete[] ptr; }
};
Run Code Online (Sandbox Code Playgroud)

const在拷贝构造函数和两个doNotChangeMyData功能让这个ptr不能改变的; 但是,这仍然允许我修改指向的数组的内容ptr

有没有办法防止仅ptrconst实例中更改 's 数组的内容,而不是“小心”(或远离原始指针)?

我知道我可以做类似的事情

void doNotChangeMyData() const {
    const double *const ptr = this->ptr;
    ptr[43] = 14; // then this would …
Run Code Online (Sandbox Code Playgroud)

c++ constants

9
推荐指数
1
解决办法
356
查看次数

C++ 编译器错误:“之前的声明符无效”

这是我的代码。编译时出现错误

\n\n
\n

\xe2\x80\x98geometry\xe2\x80\x99 之前的声明符无效

\n
\n\n

在第 16 行和第 48 行,我不确定我做错了什么。请指教。

\n\n
#include <iostream>\n#include <memory>\n#include <vector>\nusing namespace std;\nclass FactGeometry {   //Factory class\npublic:\n    static std::shared_ptr<FactGeometry>geometry( int choice );\n    virtual void calcArea() = 0;\n};\n\nclass CalcRectangle :public FactGeometry {\n    void calcArea() {\n        double ll, bb, Area;\n        std::cout << "\\nEnter the length = ";\n        std::cin >> ll;\n        std::cout << "\\nEnter the breadth = ";\n        std::cin >> bb;\n        Area = ll * bb;\n        std::cout << "\\nArea = " << Area;\n    }\n}; //end class\n\nclass CalcTraingle …
Run Code Online (Sandbox Code Playgroud)

compiler-errors factory-method shared-ptr make-shared c++11

8
推荐指数
1
解决办法
1万
查看次数

使用 memcpy 和 memset 重新分配数组

我接管了一些代码,并遇到了一个奇怪的数组重新分配。这是一个 Array 类中的函数(由 JsonValue 使用)

void reserve( uint32_t newCapacity ) {
    if ( newCapacity > length + additionalCapacity ) {
        newCapacity = std::min( newCapacity, length + std::numeric_limits<decltype( additionalCapacity )>::max() );
        JsonValue *newPtr = new JsonValue[newCapacity];

        if ( length > 0 ) {
            memcpy( newPtr, values, length * sizeof( JsonValue ) );
            memset( values, 0, length * sizeof( JsonValue ) );
        }

        delete[] values;

        values = newPtr;
        additionalCapacity = uint16_t( newCapacity - length );
    }
}
Run Code Online (Sandbox Code Playgroud)

我明白这一点;它只是分配一个新数组,并将旧数组中的内存内容复制到新数组中,然后将旧数组的内容清零。我也知道这样做是为了防止调用析构函数和移动。

JsonValue是一个带有函数的类,以及一些存储在联合中的数据(字符串、数组、数字等)。

我担心的是这是否实际上是定义的行为。我知道它有效,并且自从我们几个月前开始使用它以来一直没有问题;但如果它未定义,那么并不意味着它会继续工作。 …

c++ memory-reallocation

6
推荐指数
1
解决办法
353
查看次数

在构建 UB 期间是否将参考信息从子级传递给父级?

以下是一些代码的简化版本。

struct Test {
    Test( int &id ) : id( id ) {}
    int &id;
};

struct B : Test {
    B() : Test( a ) {}
    int a;
};
Run Code Online (Sandbox Code Playgroud)

现在,我知道在这种情况下,当创建对象时,父级Test将在B对象之前创建。B那么这是否意味着a传递给Test构造函数的变量还没有地址,因此是未定义的行为?或者这样安全吗?

只是为了澄清,直到完全构建之后id使用的值。B

c++ undefined-behavior

6
推荐指数
1
解决办法
128
查看次数

将多个值插入到特定位置的向量中

假设我有一个这样的整数向量,std::vector<int> _data; 我知道如果我想从中删除多个项目_data,那么我可以简单地调用

_data.erase( std::remove_if( _data.begin(), _data.end(), [condition] ), _data.end() );
Run Code Online (Sandbox Code Playgroud)

这比eraseing 多个元素要快得多,因为vector. 我想知道插入是否有类似的东西。

例如,如果我有以下对

auto pair1 = { _data.begin() + 5, 5 };
auto pair2 = { _data.begin() + 12, 12 };
Run Code Online (Sandbox Code Playgroud)

我可以使用一些现有std函数在一次迭代中插入这两个吗?我知道我可以这样做:

_data.insert( pair2.first, pair2.second );
_data.insert( pair1.first, pair1.second );
Run Code Online (Sandbox Code Playgroud)

但这对于大向量(谈论 100,000+ 个元素)来说(非常)慢。

编辑:基本上,我有一个自定义集(和地图),它使用 avector作为底层容器。我知道我可以只使用std::setor std::map,但是我执行的遍历次数远远超过插入/删除次数。从 aset和切换map到这个自定义集/地图已经减少了 20% 的运行时间。但目前,插入占用了大约 10% 的剩余运行时间,因此减少这一点很重要。

不幸的是,该订单也是必需的。我尽可能使用unordered_版本,但在某些地方,顺序确实很重要。

c++ vector

5
推荐指数
1
解决办法
797
查看次数

sizeof 总是一样的吗?

我有一个关于类结构、填充和由此产生sizeof的类的快速问题。在下面的示例中,在我测试过的每个编译器上,结果始终为 40 个字节sizeof A,这对我来说很有意义。

#include <iostream>
class A {
    int a, b; // 4 + 4
    short c;  // + 2
    double f; // not currently 8 byte aligned. Currently 10 bytes, so pad 6 extra bytes, so: + 6 + 8
    char w;   // + 1
    bool d;   // + 1
    double g; // not currently 8 byte aligned. Currently 26 bytes, so pad 6 extra bytes, so: + 6 + 8

    // 4 + …
Run Code Online (Sandbox Code Playgroud)

c++ sizeof

5
推荐指数
2
解决办法
192
查看次数

Visual Studio 中的警告 C6385

我似乎从 Visual Studio 2019(16.5 预览版,但也在 16.4 及更早版本中)代码分析工具收到错误警告消息。这是一个错误,还是我真的只是错过了什么?

生成的警告(确切地说)是:

警告 C6385:从“prodlist”读取无效数据:可读大小为“(size_t)*32+8”字节,但可以读取“64”字节。

这是生成警告的代码(尽可能少)

#include <cstdint>
#include <string>
#include <iostream>

struct Product {
    std::string price_profile;
};

int getNumRows() {
    return 5;
}

Product *getProductsFromDB( int &numelements ) {
    numelements = 0;

    const int num_rows = getNumRows();
    if ( num_rows == 0 ) {
        numelements = 0;
        return nullptr;
    }

    Product *prodlist = new Product[num_rows];
    for ( int i = 0; i < num_rows; ++i ) {
        prodlist[i].price_profile = "test"; // Warning on this …
Run Code Online (Sandbox Code Playgroud)

c++ sal microsoft.codeanalysis visual-studio-2019

5
推荐指数
1
解决办法
2992
查看次数

为什么 GTK 4 报告“断言‘GTK_IS_WIDGET (widget)’失败”?

我创建了我认为最简单的 GTK 4 应用程序来创建一个带有菜单栏的窗口,GAction当单击菜单项时,该菜单栏会激活 。

#include <stdio.h>
#include <assert.h>
#include <gtk/gtk.h>

static void
activate_quit(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
    printf("Quit activated\n");
}

static void
startup(GApplication *app, gpointer user_data)
{
    assert(user_data == NULL);
    char *menubar_ui = (
        "<interface>"
        "   <menu id='menubar'>"
        "       <submenu>"
        "           <attribute name='label' translatable='yes'>_File</attribute>"
        "           <section>"
        "               <item>"
        "                   <attribute name='label' translatable='yes'>_Quit</attribute>"
        "                   <attribute name='action'>app.quit</attribute>"
        "                   <attribute name='accel'>&lt;Primary&gt;q</attribute>"
        "               </item>"
        "           </section>"
        "       </submenu>"
        "   </menu>"
        "</interface>"
    );
    GtkBuilder *builder = gtk_builder_new_from_string(menubar_ui, -1);
    GObject *menubar …
Run Code Online (Sandbox Code Playgroud)

c gtk glib gtk4

5
推荐指数
1
解决办法
3154
查看次数