2014-04-04 40 views
2

我有一个自定义赋值运算符的类,故意引入受控副作用。可以std :: set :: insert()调用赋值运算符吗?

如果我有这些元素的std::set,我想知道赋值运算符是否可以使用insert来调用。

即:

class A 
{ 
public: 
    A & operator=(A const & rhs) 
    { 
     // custom assignment operator with deliberate side effects 
     // Could this be called with use of std::set::insert()? 
    } 
}; 

std::set<A> a; 

// Is it possible with this, or any use of "insert", that 
// the assignment operator will ever be called? 

a.insert(A()); 

能否赋值运算符曾与使用std::set::insert叫?

+1

有什么副作用?你可以调试代码吗? ,找出最好的方法是在'operator =' – Raxvan

+0

@Dan Nissenbaum里面放一个断点,经过一次小测试后,似乎'operator ='是**不被**调用。 – Raxvan

+0

@JoachimPileborg这将告诉他他的当前实现是否在他测试的特定情况下使用赋值运算符。它不会告诉他是否保证不会。 –

回答

1

的C++ 11标准要求与std::set::insert被用来为“CopyInsertable ”类型,“MoveInsertable”或“EmplaceConstructible”,这取决于要使用的插入功能(23.2.3/4)。

这例如定义为:

T是EmplaceConstructible成X从指定参数时,零个或多个参数指定参数时,意味着以下表达式是合式:allocator_traits<A>::construct(m, p, args);(23.2.1/13)

在所有这三种情况下,默认行为是std::allocator它采用放置新(17.6.3.5/2):

::new((void*)c)A(forward<Args>(args)...) 

取决于insert函数,在我们的示例中,args是类型A的表达式,类型为A的右值或其他一些参数。但在任何情况下,都会使用构造函数或复制构造函数,而不是赋值运算符。

这就是标准所说的(和GCC 4.6.3)。即使没有理由使用赋值运算符,某些编译器仍可能会这样做。所以我建议不要太依赖它。

3

在pre-C++ 11中,理论上可以。 C++ 11禁止它,毫无疑问,因为没有实现实际上做到了这一点,所以 。在C++ 11中,的成员 不必支持赋值。 在pre-C++ 11中,支持概念的某些实现可能会使用分配代码 ,作为检查您的类是否支持它的代码的一种方法,但它应该位于未评估的 上下文中,所以操作员不会实际上被称为。

+1

'set'的元素可能不必支持赋值,但如果存在标准禁止使用它吗?人们可能会期望一个实现有两个代码路径:一个为赋值而优化,另一个为“典型”,并在编译时使用类型特征选择其中一个。 –

+0

@MatthieuM。这是个好问题。我不认为标准直接解决它,但是...因为它没有对赋值运算符施加任何约束,实现无法指望它按照预期行事,因此无法使用它。 (实际上,正如我所说的,实际上没有实际使用它,这就是为什么标准不再需要它。) –

+1

@MatthieuM。和James Kanze - 我发现在发布模式下,Visual Studio 2013中的优化器使用赋值运算符而不是构造函数来执行批量“insert”。当我在调试模式下构建和运行相同的代码时,赋值运算符从不被调用。但是,在发布模式下,相同的代码会调用赋值运算符。这是向我显示的,因为我的副作用是在插入时触发的,但仅在释放模式下(并且我在赋值运算符中仅通过'throw'显式确认它,这只在释放模式下触发)。 –