小编Ami*_*rsh的帖子

为什么unique_ptr不会阻止自定义删除程序的切片?

std::unique_ptrwith 的行为custom deleter基于删除程序的静态类型。没有多态性,没有基于在运行时传递的实际删除程序的运行时行为,因为提供的派生删除程序已被切片为声明的删除程序的静态类型。

(其目的是通过这种方式设计的,以允许带有default deleter或带有的unique_ptr的custom deleter without any data members大小与原始指针的大小相同)。

unique_ptrwith的静态行为custom deleter

class A {};

struct BaseDeleter {
    virtual void operator()(A* p) const {
        std::cout << "in BaseDeleter" << std::endl; 
        delete p;
    }
};

struct DerivedDeleter: BaseDeleter {
    void operator()(A* p) const override {
        std::cout << "in DerivedDeleter" << std::endl; 
        delete p;
    }
};

int main() {
    auto unique_var = std::unique_ptr<A, BaseDeleter>(new A);
    unique_var = std::unique_ptr<A, DerivedDeleter>(new A); …
Run Code Online (Sandbox Code Playgroud)

c++ unique-ptr object-slicing

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

带有模板化基类的“静态数据成员的定义在其类的范围内”的规范规则

C++ 规范(例如C++17 [class.static] §2)说:

静态数据成员的定义在其类的范围内。

举个例子(取自C++14 规范):

int g();
struct X {
  static int g();
};
struct Y : X {
  static int i;
};
int Y::i = g();                 // equivalent to Y::g();
Run Code Online (Sandbox Code Playgroud)

规范中的确切措辞和示例多年来发生了变化,由于某些未知原因,C++11C++14具有与上述非常相似的示例,C++17C++20更喜欢初始化示例来自静态数据成员。在C ++ 20措辞也更准确。但似乎这条规则并没有实际的变化。


似乎这条规则不适用于模板化类的继承:

template<int VALUE>
struct base {
    static int foo() { return VALUE; }
    static constexpr int z = -1;
};

template<int VALUE>
struct foobar: base<VALUE> {
    static int …
Run Code Online (Sandbox Code Playgroud)

c++ static scope definition language-lawyer

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

在 C++ 中推导两个类的共享基数

我几乎可以肯定,如果没有反思,我正在寻找的东西就无法完成,而反思还没有出现在语言中。但有时我会对 SO 中的特殊答案感到惊讶,所以让我们尝试一下。

\n

是否可以推导出具有共同共享基类的两种类型的“common_base”,因此以下内容是可能的(伪代​​码! -语言中没有 ,这就是我想要实现的魔力) :common_base_t

\n
template<typename T1, typename T2>\nconst common_base_t<T1, T2>& foo(const T1& a1, const T2& a2) {\n    if(a1 < a2) return a1;\n    return a2;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,上面a1的 和a2并不共享 a common_type,只是作为兄弟(共享相同的基数),因此我们不能使用三元运算符。

\n

另请注意,将上述返回类型更改为 并const auto&不能解决问题(它不会编译:auto return type 的推导不一致)。

\n

这是 na\xc3\xafve 实现,要求调用者声明预期的返回类型:

\n
template<typename R>\nconst R& foo(const auto& a1, const auto& a2) {\n    if(a1 < a2) return a1;\n    return a2;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

然后我们可以这样调用它: …

c++ type-traits c++-experimental

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

为继承enable_shared_from_this的类获取unique_ptr

通常我更喜欢unique_ptr从工厂回来。unique_ptr最近我遇到了为继承的类返回 a 的问题enable_shared_from_this。此类的用户可能会意外地调用shared_from_this(),尽管它不属于任何shared_ptr,这会导致std::bad_weak_ptr异常(或在 C++17 之前未定义的行为,通常作为异常实现)。

代码的简单版本:

class Foo: public enable_shared_from_this<Foo> {
    string name;
    Foo(const string& _name) : name(_name) {}
public:
    static unique_ptr<Foo> create(const string& name) {
        return std::unique_ptr<Foo>(new Foo(name));
    }
    shared_ptr<Foo> get_shared() {return shared_from_this();}
    void doIt()const {cout << "Foo::doIt() <" << name << '>' << endl;}
    virtual ~Foo() {cout << "~Foo() <" << name << '>' << endl;}
};

int main() {
    // ok behavior
    auto pb1 = …
Run Code Online (Sandbox Code Playgroud)

c++ smart-pointers shared-ptr unique-ptr c++11

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

使用模板将成员函数集声明为朋友

给出以下代码:

class A;

struct B {
    static void doIt(A* pa);
};

struct C {
    static void doIt(A* pa);
};

class A {
    int i = 9;
    // below works but requires a line per each type
    friend void B::doIt(A* pa);
    friend void C::doIt(A* pa);

    // the below however doesn't work
    // template<typename T>
    // friend void T::doIt(A* pa);
      // (gcc error: member 'void T::doIt(A*)' declared as friend before type 'T' defined)
      // (clang just ignores the above and the error …
Run Code Online (Sandbox Code Playgroud)

c++ templates friend

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

为什么没有阻止std :: initializer_list的移动分配?

很明显,std :: initializer_list不是一个实际的容器.该标准明确定义了使用std :: initializer_list可以做什么和不能做什么.

但是为什么语言会保留做愚蠢事情的选择,比如将一个临时的std :: initializer_list分配给另一个 - 当它可以在std :: initializer_list的移动赋值运算符上用= delete时很容易被阻塞

这是一个破解的代码示例,它编译:

void foo(std::initializer_list<int> v) {
    std::cout << *v.begin() << std::endl;
}

int main() {
    int a = 1, b = 2, c = 3;
    auto val = {a, b, c}; // ok, extending the lifetime of {a, b, c}
    foo(val); // prints ok
    int i = 7;
    val = {i}; // doesn't handle well assignment of temporary
    foo(val); // prints garbage...
}
Run Code Online (Sandbox Code Playgroud)

输出,由@nwp提供: …

initializer-list c++11

5
推荐指数
0
解决办法
149
查看次数

重载 operator delete 而不重载 new 时的正确行为是什么?gcc 和 clang 不同

以下代码与clang(x86_64-pc-linux-gnu 上的版本 5.0.0-3~16.04.1)和gcc (9.2.0) 的行为不同。

void operator delete(void* ptr) noexcept {
    std::cout << "overloaded delete" << std::endl;
    free(ptr);
}

int main() {
    int* pint = new int;
    delete pint; // clang doesn't go through overloaded operator delete, gcc does
}
Run Code Online (Sandbox Code Playgroud)

gcc通过重载,operator deleteclang避免它更喜欢global delete.

(当添加重载时,operator new两个编译器都同意并通过两个重载版本)。

代码:http : //coliru.stacked-crooked.com/a/0903bd53a8c04a9b

c++ gcc operator-overloading clang overload-resolution

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

自 C++20 以来保持或传递不可寻址的函数

C++20 增加了可寻址函数 规则16.5.4.2.1 [namespace.std]/6 : -- 重点是我的 --

F表示标准库函数([global.functions])、标准库静态成员函数或标准库函数模板的实例化。除非F被指定为 可寻址函数,否则C++ 程序的行为是未指定的(可能格式错误),如果它显式隐式地尝试形成指向 F 的指针。 [注意:形成此类指针的可能方法包括应用一元 &运算符 ([expr.unary.op])、addressof ([specialized.addressof]) 或函数到指针的标准转换 ([conv.func])。— 尾注 ] 此外,如果 C++ 程序试图形成对 F 的引用,或者如果它试图形成一个指向成员的指针来指定标准库非静态成员函数([member .functions]) 或标准库成员函数模板的实例化。

据我所知,数学函数没有被规范标记为可寻址函数

这是否意味着以下代码自 C++20 以来是非法的(如cppreference和其他标准库函数的示例所指出的):

// unspecified and illegal?
auto func = static_cast<float (*)(float, float)>(std::pow);
std::cout << func(2, 4) << std::endl;
Run Code Online (Sandbox Code Playgroud)

下面的代码呢,它合法吗?

// legal? or unspecified and illegal?
std::function<float(float, float)> f = static_cast<float(*)(float, float)>(std::pow);
std::cout …
Run Code Online (Sandbox Code Playgroud)

c++ function-pointers language-lawyer c++20

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

一个朋友的缩写模板函数——clang和gcc的区别

以下代码使用 clang 编译,但不使用 gcc 编译

template<typename T>
class number {
    T num;
public:
    number(T num = 0): num(num) {}
    
    friend auto add(auto a, auto b);
};

auto add(auto a, auto b) {
    // the decltype(a) is needed to make clang happy
    // see: /sf/ask/4394546971/
    return number<decltype(a)>{a}.num + number<decltype(b)>{b}.num;
}

int main() {
    auto result = add(1.0, 2.0);
}
Run Code Online (Sandbox Code Playgroud)

gcc 提供的编译错误(版本 10.1 with -std=c++20):

In instantiation of 'auto add(auto:13, auto:14) [with auto:13 = double; auto:14 = double]':
error: 'double …
Run Code Online (Sandbox Code Playgroud)

c++ gcc templates auto c++20

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

在 C++20 中增加 易失性,不推荐对易失性进行操作

C++20 弃用了类型上的某些特定操作volatile(遵循P1152)。

以下代码在 C++20 之前有效:

void busyLoop(std::size_t count) {
  for (volatile size_t counter = 0; counter < count; ++counter);
}
Run Code Online (Sandbox Code Playgroud)

现在生成弃用警告:

warning: '++' expression of 'volatile'-qualified type is deprecated [-Wvolatile]
Run Code Online (Sandbox Code Playgroud)

更改++to+=或 tocounter = counter + 1没有帮助,因为问题似乎在于基于易失性类型计算新值。

上面的代码如何调整以适应新的C++20规则?

c++ volatile deprecated c++20

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