使用C++ 11中显式删除的成员函数,是否仍然值得从不可复制的基类继承?
我在谈论私有继承基类的技巧,该基类具有私有或删除的复制构造函数和复制赋值(例如boost::noncopyable).
这个问题提出的优势是否仍适用于C++ 11?
我不明白为什么有些人声称在C++ 11中使类不可复制更容易.
在C++ 03中:
private:
MyClass(const MyClass&) {}
MyClass& operator=(const MyClass&) {}
Run Code Online (Sandbox Code Playgroud)
在C++ 11中:
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
Run Code Online (Sandbox Code Playgroud)
编辑:
正如许多人所指出的那样,为私有拷贝构造函数和拷贝赋值运算符提供空体(即{})是错误的,因为这将允许类本身调用那些运算符而没有任何错误.我首先开始没有添加{},但遇到了一些链接器问题,这些问题让我添加{}有些愚蠢的原因(我不记得这些情况).我知道更清楚.:-)
我正在尝试使用此代码来演示复制构造函数的用法.我的假设是,当我有一个按值返回的函数时,默认情况下,我的编译器将执行对象的移动.但是当move-constructor不可用时,编译器将复制(在C++ 03中,编译器在返回by-value时会复制).那么为什么在下面的例子中编译器会尝试调用显式删除的move-constructor而不是可用的copy-constructor呢?我在GCC 4.7.2中编译了这个.
struct S
{
S() = default;
S(S const &) = default;
S(S&&) = delete;
};
S f() { return S{}; }
int main()
{
f();
}
Run Code Online (Sandbox Code Playgroud)
prog.cpp:在函数中
‘S f()’:
prog.cpp:8:18:错误:使用已删除的函数‘S::S(S&&)’
prog.cpp:5:5:错误:在此声明
下面的代码在g ++ 4.9.2和clang ++ 3.7.0下表现不同.哪一个是正确的?标准中的哪一部分与此相关?谢谢.
#include <iostream>
using namespace std;
struct Base {
Base() = default;
Base(const Base&) = default;
Base(Base&&) = delete;
};
struct Derived : Base {
};
int main() {
const Base& b = true ? Derived() : Base();
}
Run Code Online (Sandbox Code Playgroud)
g ++接受它并且clang ++给出错误incompatible operand types ('Derived' and 'Base').请参阅下文了解详情.
[hidden]$ g++ -v
Using built-in specs.
COLLECT_GCC=/usr/bin/g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.9.2/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id …Run Code Online (Sandbox Code Playgroud) 我想要相处std::function.从这里引用可以看出,对std::functionctor的论证应该是可调用的并且可以复制构造.所以这是一个小例子:
#include <iostream>
#include <type_traits>
#include <functional>
class A {
public:
A(int a = 0): a_(a) {}
A(const A& rhs): a_(rhs.a_) {}
A(A&& rhs) = delete;
void operator() ()
{
std::cout << a_ << std::endl;
}
private:
int a_;
};
typedef std::function<void()> Function;
int main(int argc, char *argv[])
{
std::cout << std::boolalpha;
std::cout << "Copy constructible: "
<< std::is_copy_constructible<A>::value << std::endl;
std::cout << "Move constructible: "
<< std::is_move_constructible<A>::value << std::endl;
//Function f = A(); …Run Code Online (Sandbox Code Playgroud) 根据标准,复制构造函数std::optional<T>:
......除非
is_copy_constructible_v<T>是,否则应被定义为删除true.
但是移动构造函数std::optional<T>:
......除非
is_move_constructible_v<T>是,否则不得参与超载决议true.
据我了解删除的构造函数,不删除move-constructor的目的std::optional<T>是允许这样的代码:
std::optional<X> o1;
std::optional<X> o2(std::move(o1));
Run Code Online (Sandbox Code Playgroud)
......依靠一些转换序列工作 - o2将由一个A使用a构造的类型的对象构造std::optional<X>&&(如果我错了,请纠正我).
但是对于可能的构造函数std::optional,我很难找到一个可以匹配这个用例的...
为什么移动构造函数std::optional<T>根本不被删除,如果T不是可移动构造的?
我不明白为什么下面的代码打印struct Value而不是int(这意味着转换构造函数转换为Value而不是int).(Visual C++ 2012)
为什么会这样?为什么编译器完全忽略Value(int)构造函数?
#include <iostream>
#include <type_info>
using namespace std;
struct Value { Value(int) { } };
struct Convertible
{
template<class T>
operator T() const
{ throw typeid(T).name(); }
};
int main()
{
try { Value w((Convertible())); }
catch (char const *s) { cerr << s << endl; }
}
Run Code Online (Sandbox Code Playgroud)
更奇怪的是这次(这次只是C++ 11,在GCC 4.7.2上):
#include <iostream>
#include <typeinfo>
using namespace std;
struct Value
{
Value(Value const …Run Code Online (Sandbox Code Playgroud) 可能重复:
为什么C++ 11删除的函数参与重载解析?
我有两个关于以下C++ 11代码的问题:
#include <iostream>
using namespace std;
struct A {
A() { cout << "Default c-tor" << endl; }
A(const A&) { cout << "Copy c-tor" << endl; }
A(A&&) = delete;
};
A f()
{
A a;
return a;
}
int main()
{
A b = f();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我用gcc和clang得到以下编译错误
gcc-4.7.2(g ++ --std = c ++ 11 main.cpp):
main.cpp: In function ‘A f()’:
main.cpp:16:9: error: use of deleted function ‘A::A(A&&)’
main.cpp:8:2: error: declared here
main.cpp: …Run Code Online (Sandbox Code Playgroud) 在做了一些研究之后,我发现C++ 11的分配器存在缺陷,需要类型可移动/可复制.我确定这是导致这个问题的原因,但我对删除和未声明的移动语义之间的行为感到困惑.
我有以下代码无法在MSVC12和Clang上编译:
#include <vector>
class Copyable
{
public:
Copyable() = default;
Copyable(Copyable const& other)
: m_int(other.m_int)
{}
Copyable& operator= (Copyable const& other)
{
m_int = other.m_int;
return *this;
}
Copyable(Copyable&&) = delete;
Copyable& operator= (Copyable&&) = delete;
private:
int m_int = 100;
};
int main()
{
std::vector<Copyable> objects;
objects.push_back(Copyable{});
}
Run Code Online (Sandbox Code Playgroud)
这无法在MSVC上编译:
xmemory0(600):错误C2280:'可复制::可复制(可复制&&)':尝试引用已删除的函数
而对于Clang(现场样本):
new_allocator.h:120:23:错误:调用'Copyable'的已删除构造函数
在这两种情况下,当我删除显式删除的移动构造/分配方法时,代码编译.AFAIK在声明复制赋值/构造方法时,编译器不会隐式声明相应的移动成员.所以它们仍应被有效删除,对吧?当我删除move construct/assign的显式删除时,为什么代码会编译?
一般来说,这个C++ 11缺陷有什么好的解决方法?我不希望我的物体可以移动(但它们是可复制的).
template <typename T>
class A {
public:
template<class C> A(const A<C>&) {}
A(A&&) {}
};
void f(A<int>& a)
{
A<int> b(a);
}
Run Code Online (Sandbox Code Playgroud)
上面的代码不能在g ++/clang ++中编译报告复制构造函数因为用户提供的移动构造函数而被删除(尽管vc ++编译好了).是否有任何标准要求阻止在重载解析期间选择模板构造函数(我知道它不是复制构造函数)?或者是否要求初始化程序与initializee具有相同的类型时,它必须选择复制构造函数?
例如,代码如下:
struct A { A(int); };
struct B { B(A); };
int main()
{
B b{{0}}; // OK
B c({0}); // error
}
Run Code Online (Sandbox Code Playgroud)
错误消息是:
f.cc: In function 'int main()':
f.cc:7:9: error: call of overloaded 'B(<brace-enclosed initializer list>)' is ambiguous
B c({0}); // error
^
f.cc:7:9: note: candidates are:
f.cc:2:12: note: B::B(A)
struct B { B(A); };
^
f.cc:2:8: note: constexpr B::B(const B&)
struct B { B(A); };
^
f.cc:2:8: note: constexpr B::B(B&&)
Run Code Online (Sandbox Code Playgroud) c++ ×10
c++11 ×6
gcc ×2
c++14 ×1
clang ×1
constructor ×1
noncopyable ×1
optional ×1
templates ×1
visual-c++ ×1